之前在BlogJava上发表过这篇文章,那时没怎么做整理。想不到已经有博友把它弄到ITEye来了(虽然写得水平差,但还是希望那位博友能注明是转载的)。这次稍作了整理,自己也加深下印象。
使用场景:用于生成实体主键键值,每次增长1。
框架支持:spring,hibernate
工作方式:单例,序列号生成器支持缓存键值,可设定每次取键的个数。用于集群环境时,取键个数设为1即可。
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.pro.base.model.TableKey;
import com.pro.base.service.BasicService;
/***
* 基于单例模式的多键值带缓存序列号生成器
*
* 思路:
* 数据库表通过Hibernate映射为实体类,主键通过序列号生成器(KeyGenerator)生成;
* 序列号生成器以Singleton方式工作,并维护所有需要维护的实体的序列号(KeyBean);
* 列号生成器缓存一定的键值,避免每次取序列号都从数据库获取;
* 数据库建立实体和当前键值对应表,每从列号生成器获取一个序列时,同步到该键值对应表,避免宕机后不一致
*
* @author o_oand0_0
*
*/
public class KeyGenerator implements ApplicationContextAware {
//实现ApplicationContextAware,Spring对applicationContext自动装配
private ApplicationContext applicationContext;
//键值实体类
private Map<String, KeyBean> keyMap;
//数据库服务
private BasicService basicService;
//设置要缓存的键值的数量,建议在团队开发测试时设为1,省得总出现主键冲突,到上线后再调大
//另外集群环境下使用时,需要把该值设为1,相当于每次取键值的时候同时更新数据库
private static long keyNum=20;
private static final KeyGenerator instance=null;
private KeyGenerator() {
basicService=(BasicService)applicationContext.getBean("basicService");
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext=applicationContext;
}
//以单例方式获取序列号生成器
public static synchronized KeyGenerator getInstance(){
if(instance==null){
return new KeyGenerator();
}else{
return instance;
}
}
/**
* 根据类名获取序列号
* @param clazz
* @return
*/
public String generatorKey(Class clazz){
return getKey(clazz);
}
/**
* 生成序列号,并同步至数据库
* 此方法可以根据自己需要定义生成序列号的规则
* @param clazz
* @return
*/
public String getKey(Class clazz) {
if (keyMap == null) {
keyMap = new ConcurrentHashMap<String, KeyBean>();
}
KeyBean kb = keyMap.get(clazz.getName());
if (kb == null||kb.getMaxIndex()==kb.getNowIndex()) {
updateKeyBean(clazz.getName());
}
kb = keyMap.get(clazz.getName());
long now=kb.getNowIndex();
kb.setNowIndex(now+1);
return now+"";
}
/**
* 同步序列值到数据库,并修改序列号生成器对应实体的下一键值
* @param classPath
*/
private void updateKeyBean(String classPath) {
TableKey tk = (TableKey) basicService.expandObjectByKey(TableKey.class.getName(),
classPath);
KeyBean kb=new KeyBean();
kb.setKeyName(classPath);
try {
if (tk == null) {
tk=new TableKey();
kb.setMaxIndex(keyNum);
kb.setNowIndex(1);
tk.setTableName(classPath);
tk.setNowIndex(""+keyNum);
basicService.insert(tk);
} else {
kb.setMaxIndex(keyNum+Long.valueOf(tk.getNowIndex()));
kb.setNowIndex(Long.valueOf(tk.getNowIndex()));
tk.setNowIndex(Long.valueOf(tk.getNowIndex()) + keyNum + "");
basicService.update(tk);
}
keyMap.put(classPath, kb);
} catch (Exception e) {
e.printStackTrace();
}
}
public Map<String, KeyBean> getKeyMap() {
return keyMap;
}
public void setKeyMap(Map<String, KeyBean> keyMap) {
this.keyMap = keyMap;
}
public BasicService getBasicService() {
return basicService;
}
public void setBasicService(BasicService basicService) {
this.basicService = basicService;
}
/***
* 键值实体类
* @author o_oand0_0
*
*/
protected class KeyBean {
private String keyName;
private long nowIndex;
private long maxIndex;
public String getKeyName() {
return keyName;
}
public void setKeyName(String keyName) {
this.keyName = keyName;
}
public long getNowIndex() {
return nowIndex;
}
public void setNowIndex(long nowIndex) {
this.nowIndex = nowIndex;
}
public long getMaxIndex() {
return maxIndex;
}
public void setMaxIndex(long maxIndex) {
this.maxIndex = maxIndex;
}
}
}
/**
* TableKey 实体.
* 记录实体的类名和当前的索引号,对应数据库表table_key
* @author o_oand0_0
*/
public class TableKey implements java.io.Serializable {
// Fields
private String tableName;
private String nowIndex;
// Constructors
/** default constructor */
public TableKey() {
}
/** full constructor */
public TableKey(String tableName, String nowIndex) {
this.tableName = tableName;
this.nowIndex = nowIndex;
}
// Property accessors
public String getTableName() {
return this.tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getNowIndex() {
return this.nowIndex;
}
public void setNowIndex(String nowIndex) {
this.nowIndex = nowIndex;
}
}
需要在applicationContext.xml中生成器:
<bean name="keyGenerator" class="com.pro.base.util.KeyGenerator"> <property name="basicService" ref="basicService"></property> </bean>
使用方法:
String keyId = KeyGenerator.getInstance().getKey(Attachments.class);