`
o_oand0_0
  • 浏览: 20213 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类

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

阅读更多

之前在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);
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics