基于单例模式的多键值序列号生成器实现(带缓存)
基本思路:
* 数据库表通过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
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44

45
46
47
48
49
50

51
52
53
54
55

56

57
58

59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78

79

80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101

102

103
104
105
106
107
108
109

110
111
112
113
114
115
116

117
118
119
120
121

122
123
124
125

126
127
128
129

130
131
132
133
134

135
136
137
138
139
140
141
142
143

144
145
146
147
148

149
150
151
152

153
154
155
156

157
158
159
160

161
162
163
164

165
166
167
168

169
170
171
172
173
174