基于单例模式的多键值序列号生成器实现(带缓存)
基本思路:
?* 数据库表通过Hibernate映射为实体类,主键通过序列号生成器(KeyGenerator)生成;
?* 序列号生成器以Singleton方式工作,并维护所有需要维护的实体的序列号(KeyBean);
?* 列号生成器缓存一定的键值,避免每次取序列号都从数据库获取;
?* 数据库建立实体和当前键值对应表,每从列号生成器获取一个序列时,同步到该键值对应表,避免宕机后不一致
package?com.pro.base.util;
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自动装配;需要把KeyGenerator配置到Spring容器
????private??ApplicationContext?applicationContext;
????//键值实体类
????private?Map<String,?KeyBean>?keyMap;
????
????//数据库服务
????private?BasicService?basicService;
????
????//设置要缓存的键值的数量,建议在团队开发测试时设为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;
????????}
????}
????
}