o_oand0_0

软件开发
随笔 - 4, 文章 - 2, 评论 - 5, 引用 - 0
数据加载中……

基于单例模式的多键值序列号生成器实现(带缓存)


基本思路:
 * 数据库表通过Hibernate映射为实体类,主键通过序列号生成器(KeyGenerator)生成;
 * 序列号生成器以Singleton方式工作,并维护所有需要维护的实体的序列号(KeyBean);
 * 列号生成器缓存一定的键值,避免每次取序列号都从数据库获取;
 * 数据库建立实体和当前键值对应表,每从列号生成器获取一个序列时,同步到该键值对应表,避免宕机后不一致
  1package com.pro.base.util;
  2
  3import java.util.Map;
  4import java.util.concurrent.ConcurrentHashMap;
  5import org.springframework.beans.BeansException;
  6import org.springframework.context.ApplicationContext;
  7import org.springframework.context.ApplicationContextAware;
  8
  9import com.pro.base.model.TableKey;
 10import com.pro.base.service.BasicService;
 11
 12/***
 13 * 基于单例模式的多键值带缓存序列号生成器
 14 * 
 15 * 思路:
 16 * 数据库表通过Hibernate映射为实体类,主键通过序列号生成器(KeyGenerator)生成;
 17 * 序列号生成器以Singleton方式工作,并维护所有需要维护的实体的序列号(KeyBean);
 18 * 列号生成器缓存一定的键值,避免每次取序列号都从数据库获取;
 19 * 数据库建立实体和当前键值对应表,每从列号生成器获取一个序列时,同步到该键值对应表,避免宕机后不一致
 20 * 
 21 * @author o_oand0_0
 22 *
 23 */

 24public class KeyGenerator implements ApplicationContextAware {
 25    
 26    //实现ApplicationContextAware,Spring对applicationContext自动装配;需要把KeyGenerator配置到Spring容器
 27    private  ApplicationContext applicationContext;
 28
 29    //键值实体类
 30    private Map<String, KeyBean> keyMap;
 31    
 32    //数据库服务
 33    private BasicService basicService;
 34    
 35    //设置要缓存的键值的数量,建议在团队开发测试时设为1,省得总出现主键冲突,到上线后再调大
 36    private static long keyNum=20;
 37    
 38    private static final KeyGenerator instance=null;
 39    
 40    private KeyGenerator() {
 41        basicService=(BasicService)applicationContext.getBean("basicService");
 42    }

 43    
 44    public  ApplicationContext getApplicationContext() {
 45        return applicationContext;
 46    }

 47
 48    @Override
 49    public void setApplicationContext(ApplicationContext applicationContext)
 50            throws BeansException {
 51        this.applicationContext=applicationContext;
 52    }

 53    
 54    //以单例方式获取序列号生成器
 55    public static synchronized  KeyGenerator getInstance(){
 56        if(instance==null){
 57            return new KeyGenerator();
 58        }
else{
 59            return instance;
 60        }

 61    }

 62    
 63    /**
 64     * 根据类名获取序列号
 65     * @param clazz
 66     * @return
 67     */

 68    public  String generatorKey(Class clazz){
 69        return getKey(clazz);
 70    }

 71
 72    /**
 73     * 生成序列号,并同步至数据库
 74     * 此方法可以根据自己需要定义生成序列号的规则
 75     * @param clazz
 76     * @return
 77     */

 78    public String getKey(Class clazz) {
 79        if (keyMap == null{
 80            keyMap = new ConcurrentHashMap<String, KeyBean>();
 81        }

 82        KeyBean kb = keyMap.get(clazz.getName());
 83        if (kb == null||kb.getMaxIndex()==kb.getNowIndex()) {
 84            updateKeyBean(clazz.getName());
 85        }

 86        kb = keyMap.get(clazz.getName());
 87        long now=kb.getNowIndex();
 88        kb.setNowIndex(now+1);
 89        return now+"";
 90    }

 91
 92    /**
 93     * 同步序列值到数据库,并修改序列号生成器对应实体的下一键值
 94     * @param classPath
 95     */

 96    private void updateKeyBean(String classPath) {
 97        TableKey tk = (TableKey) basicService.expandObjectByKey(TableKey.class.getName(),
 98                classPath);
 99        KeyBean kb=new KeyBean();
100        kb.setKeyName(classPath);
101        try {
102            if (tk == null{
103                tk=new TableKey();
104                kb.setMaxIndex(keyNum);
105                kb.setNowIndex(1);
106                tk.setTableName(classPath);
107                tk.setNowIndex(""+keyNum);
108                basicService.insert(tk);
109            }
 else {
110                kb.setMaxIndex(keyNum+Long.valueOf(tk.getNowIndex()));
111                kb.setNowIndex(Long.valueOf(tk.getNowIndex()));
112                tk.setNowIndex(Long.valueOf(tk.getNowIndex()) + keyNum + "");
113                basicService.update(tk);
114            }

115            keyMap.put(classPath, kb);            
116        }
 catch (Exception e) {
117            e.printStackTrace();
118        }

119    }

120
121    public Map<String, KeyBean> getKeyMap() {
122        return keyMap;
123    }

124
125    public void setKeyMap(Map<String, KeyBean> keyMap) {
126        this.keyMap = keyMap;
127    }

128
129    public BasicService getBasicService() {
130        return basicService;
131    }

132
133    
134    public void setBasicService(BasicService basicService) {
135        this.basicService = basicService;
136    }

137    
138    /***
139     * 键值实体类
140     * @author o_oand0_0
141     *
142     */

143    protected class KeyBean {
144        private String keyName;
145        private long nowIndex;
146        private long maxIndex;
147
148        public String getKeyName() {
149            return keyName;
150        }

151
152        public void setKeyName(String keyName) {
153            this.keyName = keyName;
154        }

155
156        public long getNowIndex() {
157            return nowIndex;
158        }

159
160        public void setNowIndex(long nowIndex) {
161            this.nowIndex = nowIndex;
162        }

163
164        public long getMaxIndex() {
165            return maxIndex;
166        }

167
168        public void setMaxIndex(long maxIndex) {
169            this.maxIndex = maxIndex;
170        }

171    }

172    
173}

174


posted on 2011-10-21 17:15 o_oand0_0 阅读(2201) 评论(3)  编辑  收藏 所属分类: JAVA

评论

# re: 基于单例模式的多键值序列号生成器实现(带缓存)  回复  更多评论   

不错 学习了
2011-10-24 08:37 | tb

# re: 基于单例模式的多键值序列号生成器实现(带缓存)  回复  更多评论   

系统启动时应该要初始化 keyMap,不然就不一致了
2013-08-02 11:21 | y6

# re: 基于单例模式的多键值序列号生成器实现(带缓存)  回复  更多评论   

最好是在实例化KeyGenerator时自动进行
2013-08-02 11:24 | y6