`
o_oand0_0
  • 浏览: 20556 次
  • 性别: 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);
分享到:
评论

相关推荐

    cod4序列号生成器

    cod4序列号生成器 cod4序列号生成器

    数据库序列号生成器

    7. **扩展性**:对于大型系统,序列号生成器可能需要设计成可扩展的,以便在集群环境中支持多个节点同时生成序列号。 虽然具体的实现细节无法提供,但上述知识点提供了一个基本的框架,可以帮助理解数据库序列号...

    Nero Burning Rom 序列号生成器

    然而,"Nero Burning Rom 序列号生成器"涉及的话题较为敏感,因为这可能指的是一个用于生成非法或假冒软件序列号的工具,这违反了软件版权法律。 首先,让我们明确一点:合法使用软件是每个用户的义务,尊重知识...

    易语言序列号生成器

    易语言序列号生成器源码,序列号生成器,十六进制到十进制,十进制到十六进制,序列号显示,序列号算法,序列号反算,读取授权文件,秘密,wvsprintfA,StrToIntExA

    虚拟机序列号生成器.

    虚拟机序列号生成器.rar

    卡巴斯基序列号生成器

    卡巴斯基序列号生成器

    序列号生成器

    ### 序列号生成器实现解析 #### 一、概述 本文将深入解析一个Java实现的序列号生成器,该生成器主要用于在分布式系统中生成唯一标识符(ID)。通过分析其核心方法`nextId()`及辅助方法,我们将了解它是如何确保在...

    adobe-dreamwear cs4序列号生成器

    【标题】"adobe-dreamwear cs4序列号生成器"所涉及的知识点主要集中在Adobe Dreamweaver CS4这款软件的授权与激活机制上。Adobe Dreamweaver是Adobe公司开发的一款专业级网页设计和开发工具,它融合了视觉设计与代码...

    Steelray Project Viewer序列号生成器

    Steelray Project Viewer序列号生成器noy-steelray.project.viewer.keygen.jar 支持5.0以上版本,其他版本未测试 运行需安装jdk、jre 另,内含多个可用的license

    web storm 序列号生成器

    web storm 序列号生成器, 破解, 支持当前最新的WebStorm3.03, 3.03版本支持NodeJS的开发. 非常好用的JavaScript的开发工具.

    虚拟化硬件序列号生成器匿名者 v1.5.zip

    系统硬盘序列号 网卡MAC 主板信息 支持Windows10 1809 1903 1909 2004 20h2 21h1 使用方法就是依次输入1 2 3就行 重启不会自动恢复 : 随机化注册表和重置网卡数据 重启会自动恢复 : 加载匿名驱动 建议配合影子系统...

    vmware workstation 10 序列号生成器

    在描述中提到的“vmware workstation 10 序列号生成器”是指一种工具,通常这类工具是非官方的,目的是为了生成可以激活VMware Workstation 10的序列号。然而,值得注意的是,使用这种序列号生成器是违反VMware的...

    软件序列号生成器.rar

    软件序列号生成器,通取物理地址,实现对MAC地址的绑定。加密好工具。

    Balsamiq.Mockups.v2.2.3 包括序列号生成器

    描述中提到的“序列号生成器”通常是指一种用于生成软件激活码的工具。在Balsamiq Mockups的情况下,这个“keygen”可能是第三方开发的,旨在允许用户免费或非法地使用软件。使用序列号生成器违反了软件的许可协议,...

    C#自动生成序列号 源码

    在IT行业中,序列号生成是常见的...总的来说,C#自动生成序列号涉及多个知识点,包括`Guid`、`DateTime`、随机数生成以及可能的加密和验证策略。通过理解和运用这些工具,开发者可以创建出符合业务需求的序列号系统。

    单例模式 Singleton Pattern

    #### 多线程下的单例模式实现 由于单例模式涉及到全局共享资源的访问,因此在多线程环境下需要特别注意同步问题。下面是一些常见的实现方式: 1. **懒汉式,线程不安全**:这种方式简单,但是不支持多线程,容易...

    Myeclipse6.0和Myeclipse6.5序列号生成器

    在描述中提到的“代码实现”是指序列号生成器的源代码,这类工具通常是非法的,因为它们试图绕过软件的版权保护机制。序列号生成器通过模拟官方的验证算法来生成看似合法的序列号,这种行为违反了软件使用协议,并...

    eset序列号产生器

    eset 序列号生成器eset 序列号生成器eset 序列号生成器eset 序列号生成器

    eclipse序列号生成器

    【标题】"eclipse序列号生成器"涉及的是软件授权和Eclipse集成开发环境(IDE)的相关知识。Eclipse是一款开源、跨平台的Java IDE,广泛用于Java应用程序的开发,同时也支持其他编程语言如C++、Python等。然而,这里...

    序列号生成器初级代码

    在IT领域,序列号生成器通常用于软件授权验证,它基于特定算法生成一串唯一标识符,以确保软件只能在合法授权的设备上运行。在这个初级代码项目中,开发者使用了Qt库,一个跨平台的应用程序开发框架,来实现硬件信息...

Global site tag (gtag.js) - Google Analytics