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