`
uule
  • 浏览: 6348831 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

获取id 的一种策略

 
阅读更多

从数据库中批量(step个)拿出Id,然后使用,待消耗完后再批量拿出Id

 

key1 = genKey+"##"+subKey;

 

三个并发Map:

mapLock:判断是否存在锁

mapGenId:保存每次的currNo值

mapMaxId:保存每次currNo+step后的值

三个ConcurrentHashMap的key都为 key1

 

大体思路:

一、由genKey、subKey构建一个锁,获取Id值时先判断是否存在锁,当不存在锁时,先初始化

 

初始化:

从数据库中取出currNo

1、若currNo为0(第一次)

将当前currNo设为0并放入mapGenId中

表中插入一条currNo为step的记录,返回MaxId的值为step

  

2、若currNo不为0

将当前currNo设为数据库中查出的currNo,并放入mapGenId中

将数据库中查出的currNo,加上step后更新,返回MaxId的值为currNo+step

 

 

将MaxId置入保存最大值的并发map mapMaxId中

再生成key为key1的锁

 

二、初始化完成后,取得锁(若已存在锁,则取出并锁住),从mapGenId、mapMaxId中分别取得当前currNo值和当前最大MaxId值

 

若 mapGenId中取出的值(当前currNo值)<= mapMaxId中的值(每次的最大currNo值)时,说明上次取得 step个Id还没有消耗完,所以直接当前currNo+1即可,否则说明

已消耗完,需要重新从数据库中取数据

 

三、若需要重新取数据,则跟初始化时currNo不为0的情况相同

 加上 step后更新数据库,然后分别设置mapGenId、mapMaxId即可

 

 DB:



  

 

使用:

long lPointId = HttpUtil.getId("testSQL","userPoint");

public static Long getId(String genKey,String subKey){
		Long lId = 0l;		
		lId = GetTableId.getCurrentId(genKey, subKey);
		return lId;
	}

 

public class GetTableId {
	static Logger logger = Logger.getLogger(GetTableId.class);
	
	
	/**
	 * 获取ID
	 * @param genKey
	 * @param subKey
	 * @return
	 */
	public static Long getCurrentId(String genKey,String subKey){
		GenId genIdVo = new GenId();
		genIdVo.setGenKey(genKey);
		genIdVo.setSubKey(subKey);
		
		Long currNo = getGenId(genIdVo);
		return currNo;
	}
	
	
	public static Long getGenId(GenId genIdVo){
		String subKey = genIdVo.getSubKey();

		String genKey = genIdVo.getGenKey();
		
		if (!GenIdHelper.getInstance().containsKey(genKey, subKey)) {
			initGenIdByDB(genIdVo);  //初始化ID hash
		}
		synchronized (GenIdHelper.getInstance().getLockObject(genKey, subKey)) {
			
			Long currNo = getGenIdByCache(genKey, subKey);
			
			logger.info("return currNo = " + currNo);
			
			return currNo;

		}

	}

	/**
	 * 第一次加载
	 */
	private static void initGenIdByDB(GenId genIdVo) {
		String subKey = genIdVo.getSubKey();

		String genKey = genIdVo.getGenKey();

		logger.info("genKey = " + genKey + ": subKey = " + subKey);

		GenId vo = getGenIdLock(genKey, subKey);

		if (GenIdHelper.getInstance().containsKey(genKey, subKey)) {

			logger.info("other thread is return" + genKey + ":" + subKey);

			return;
		}

		Long step = GenIdConstant.GenIdStep;

		Long currNo = 0L;

		if (vo.getCurrNo() == 0) {

			currNo = insertGenId(genKey, subKey, step);

			logger.info("no live frist is currNo =" + currNo);

			GenIdHelper.getInstance().setGenIDValue(genKey, subKey, new Long(0));

		} else {

			updateGenIdVO(genKey, subKey);
			
			currNo = vo.getCurrNo() + GenIdHelper.getInstance().getGenIdSetp(genKey, subKey);

			GenIdHelper.getInstance().setGenIDValue(genKey, subKey, vo.getCurrNo());

			logger.info("live frist is currNo =" + currNo);

		}

		setGenIdCacheMap(genKey, subKey, currNo);

		GenIdHelper.getInstance().setLockObject(genIdVo.getGenKey(),genIdVo.getSubKey());

	}
	
	/**
	 * 设置CACHEMAP里的值
	 * 
	 * @param genKey
	 * @param subKey
	 * @param currNo
	 */
	private static void setGenIdCacheMap(String genKey, String subKey, Long currNo) {

		logger.info("setGenIdCacheMap genKey = " + genKey + ": subKey = " + subKey + ": currNo = " + currNo);

		GenIdHelper.getInstance().setMaxID(genKey, subKey, currNo);
	}
	
	/**
	 * 如果数据库不存在就插入
	 * 
	 * @param genKey
	 * @param subKey
	 * @param step
	 * insert into genId (currNo, genKey, subKey, updateTime) values
				({currNo}, {genKey}, {subKey}, now());
	 */
	private static Long insertGenId(String genKey, String subKey, Long step) {		
		CDO cdoRequest = new CDO();
		CDO cdoResponse = new CDO();
		cdoRequest.setStringValue(ITransService.SERVICENAME_KEY,"CommonService");
		cdoRequest.setStringValue(ITransService.TRANSNAME_KEY, "insertGenId");
		cdoRequest.setStringValue("subKey", subKey);
		cdoRequest.setStringValue("genKey", genKey);
		cdoRequest.setLongValue("currNo", step);
		Return ret = getServiceBus().handleTrans(cdoRequest, cdoResponse);
		if (ret.getCode() != 0) {
			logger.error("insertGenId error.");
		}

		return step;
	}
	
	/**
	 * 从数据库里取的时候先锁住这条记录
	 * 
	 * @param genKey
	 * @param subKey
	 * @return
	 */
	private static GenId getGenIdLock(String genKey, String subKey) {
		long lId = 0;
		logger.info("islock genKey = " + genKey + ": subKey = " + subKey);

		GenId genIdVo = new GenId();

		genIdVo.setSubKey(subKey);

		genIdVo.setGenKey(genKey);
		
		CDO cdoRequest = new CDO();
		CDO cdoResponse = new CDO();
		
		cdoRequest.setStringValue(ITransService.SERVICENAME_KEY,"CommonService");
		cdoRequest.setStringValue(ITransService.TRANSNAME_KEY, "getGenId");
		cdoRequest.setStringValue("subKey", subKey);
		cdoRequest.setStringValue("genKey", genKey);
		Return ret = getServiceBus().handleTrans(cdoRequest, cdoResponse);
		if (ret.getCode() == 0) {
			if(cdoResponse.exists("cdoGenId")){
				lId = cdoResponse.getLongValue("cdoGenId");
			}
		}
		genIdVo.setCurrNo(lId);
		return genIdVo;
	}
	
	/**
	 * 更新数据的操作
	 * 
	 * @param subKey
	 * @param genKey
	 * @param currNo
	 * update genId  set currNo = currNo + {currNo},updateTime=now() 
				where genKey = {genKey} and subKey = {subKey}
	 */
	private static void updateGenIdVO(String genKey, String subKey) {
		logger.info("updateGenIdVO genKey = " + genKey + ": subKey = " + subKey);

		long currNo = GenIdConstant.GenIdStep;

		CDO cdoRequest = new CDO();
		CDO cdoResponse = new CDO();
		cdoRequest.setStringValue(ITransService.SERVICENAME_KEY,"CommonService");
		cdoRequest.setStringValue(ITransService.TRANSNAME_KEY, "updateGenIdByPk");
		cdoRequest.setStringValue("subKey", subKey);
		cdoRequest.setStringValue("genKey", genKey);
		cdoRequest.setLongValue("currNo", currNo);
		Return ret = getServiceBus().handleTrans(cdoRequest, cdoResponse);
		if (ret.getCode() != 0) {
			logger.error("updateGenIdByPk error.");
		}

	}
	
	/**
	 * 比较当前值和最大值,返回自增ID
	 * @param genKey
	 * @param subKey
	 * @return
	 */
	private static Long getGenIdByCache(String genKey, String subKey) {
		
		Long maxId = GenIdHelper.getInstance().getMaxID(genKey, subKey)	;
		
		logger.info("getGenIdByCache maxId = " + maxId);
		
		Long currNo = GenIdHelper.getInstance().getGenIDValue(genKey, subKey);
		
		logger.info("currNo maxId = " + currNo);
		
		if(currNo >= maxId){
			
			GenId genIdVo = new GenId();
			
			genIdVo.setGenKey(genKey);
			
			genIdVo.setSubKey(subKey);
			
			setGenIdByDB(genIdVo);
		
		}
		
		GenIdHelper.getInstance().setGenIDValue(genKey, subKey, currNo + 1);

		return currNo + 1;
	}
	
	
	/**
	 * 如果大于最大值就从数据库里取
	 */
	private static void setGenIdByDB(GenId genIdVo) {

		String subKey = genIdVo.getSubKey();

		String genKey = genIdVo.getGenKey();

		logger.info("genKey = " + genKey + ": subKey = " + subKey);

		GenId vo = getGenIdLock(genKey, subKey);
		
		updateGenIdVO(genKey, subKey);

		Long currNo = vo.getCurrNo() + GenIdConstant.GenIdStep;

		logger.info("setGenIdByDB currNo = " + currNo);

		setGenIdCacheMap(genKey,subKey, currNo);

	}

}

 

public class GenId {
	
	private Long genId;
	
	private Long currNo;
	
	private String genKey;
	
	private String subKey;
        ...
}

 

public class GenIdConstant {

	public final static String SPLITFLAG = "##";
	
	public final static Long GenIdStep  = new Long(100);
	
	public final static String RESULTTYPEKEYNAME  = "resultCode";
	
	public final static String RESULTCURRNONAME  = "currNo";

	
}

 

处理并发工具类:

public class GenIdHelper {
	
	//每条记录的线程锁
	private static ConcurrentHashMap<String, Object> mapLock = new ConcurrentHashMap<String, Object>();
	
	//每个记录的步长
	private static ConcurrentHashMap<String, Long> mapStep = new ConcurrentHashMap<String, Long>();
	
	//每个记录的ID值
	private static ConcurrentHashMap<String, Long> mapGenId = new ConcurrentHashMap<String, Long>();
	
	//每个记录的MAXID值
	private static ConcurrentHashMap<String, Long> mapMaxId = new ConcurrentHashMap<String, Long>();
	
	/*
	 * 懒汉,线程安全
	 */
	private static GenIdHelper cc = null;
	
	private GenIdHelper(){}
	
	public static synchronized GenIdHelper getInstance() {
		if (cc == null){		
			cc = new GenIdHelper();
		}
		return cc;
	}
	
	/**
	 * 设置每个自增ID的线程锁对象
	 * 
	 */	
	protected  void setLockObject(String genKey, String subKey){
		
		mapLock.put(buildLockKey(genKey, subKey), new Object());
	}
	
	/**
	 * 设置每个自增ID的线程锁对象
	 * 
	 */	
	protected Object getLockObject(String genKey, String subKey){
		
		return mapLock.get(buildLockKey(genKey, subKey));
	}
	
	/**
	 * 设置每个自增ID的最大值
	 * 
	 */	
	protected  void setMaxID(String genKey, String subKey, Long maxId){
		
		mapMaxId.put(buildLockKey(genKey, subKey), maxId);
	}
	
	/**
	 * 获取自增ID的最大值
	 * 
	 */	
	protected  Long getMaxID(String genKey, String subKey){
		
		return mapMaxId.get(buildLockKey(genKey, subKey));
	}
	
	/**
	 * 获取自增ID的值
	 * 
	 */	
	protected  Long getGenIDValue(String genKey, String subKey){
		
		return mapGenId.get(buildLockKey(genKey, subKey));
	}
	
	/**
	 * 设置获取自增ID的值
	 * 
	 */	
	protected void setGenIDValue(String genKey, String subKey, Long currNo){
		
		mapGenId.put(buildLockKey(genKey, subKey), currNo);
	}
	
	/**
	 * 判断是否存在线程锁对象
	 * @param key
	 */	
	protected  boolean containsKey(String genKey, String subKey){
		
		return mapLock.containsKey(buildLockKey(genKey, subKey));
	}
	
	private  String buildLockKey(String genKey, String subKey){
		
		return genKey + GenIdConstant.SPLITFLAG + subKey;
	}
	
	protected Long getGenIdSetp(String genKey, String subKey){
		
		Long step = mapStep.get(buildLockKey(genKey, subKey));
		
		if(step == null){
			
			step = GenIdConstant.GenIdStep;
		}
		
		return step;
		
	}

}

 。。。

 

 

 

 

 

 

  • 大小: 7.5 KB
  • 大小: 44.5 KB
分享到:
评论

相关推荐

    java 获取分布式唯一ID.雪花ID

    雪花ID(Snowflake ID)是一种被广泛采用的解决方案,由Twitter开源,其设计目标就是生成全局唯一的、时间序列的64位整数ID。以下我们将详细探讨这个话题。 首先,雪花ID的结构分为6部分,共64位: 1. **符号位**...

    java自动生成id策略

    "java自动生成id策略"指的是设计并实现一种机制,确保在多线程环境下能够高效、唯一地生成ID。这里我们将详细探讨这个主题,以及如何根据描述实现这样的策略。 首先,ID的生成通常要求满足以下条件: 1. 唯一性:...

    ID生成策略

    `Sequence`是一种适用于支持序列操作的数据库系统(如DB2和Oracle)的ID生成策略。通过创建一个序列对象,每次调用序列的`NEXTVAL`方法即可获取一个新的唯一值。示例代码如下: ```sql CREATE SEQUENCE seq_name ...

    金蝶EAS开发中根据单据id获取实体名的方法

    总结来说,金蝶EAS的开发中,利用单据ID获取实体名是一种高效且灵活的编程策略,能够简化多单据功能的实现,提高代码质量。通过BOSUuid、BOSObjectType以及元数据加载器,开发者可以轻松地进行跨单据的通用功能开发...

    获取Android移动终端设备唯一ID.zip

    在Android系统中,获取移动终端设备的唯一标识是开发者经常需要进行的一项操作,这有助于跟踪设备、推送个性化服务或者实施安全策略。本资料"获取Android移动终端设备唯一ID.zip"聚焦于这一主题,旨在帮助开发者了解...

    VC获取CPU ID号

    CPU ID是处理器的一种特性,它提供了关于CPU硬件的具体信息,包括制造商、型号、步进和一些特定的功能。在Windows系统中,通过VC编写程序来获取CPU ID,可以实现软件与特定硬件的绑定,防止非法复制或盗版,这对于...

    don32 ID获取器

    总的来说,“don32 ID获取器”提供了一种解决方案,用于获取ESET DON32的有效ID和密码,并且包含了自动升级功能,这使得用户能够持续保护自己的系统免受最新威胁的侵害。然而,值得注意的是,使用第三方工具可能存在...

    分布式ID生成策略_snowflake算法

    Snowflake算法是由Twitter开源的一种高效且可扩展的分布式ID生成方案,广泛应用于Java和其他编程语言的系统中。 Snowflake算法的核心思想是将64位的整数划分为不同的部分,分别为: 1. **时间戳**(41位):自定义...

    iOS deviceid获取

    在本文中,我们将深入探讨如何在iOS应用中获取device ID,并关注`KeychainItemWrapper`这一关键组件。 首先,我们来了解几种常见的device ID类型: 1. **UDID(Unique Device Identifier)**:UDID曾是最常见的...

    获取U盘ID号C#获取U盘ID号唯一标识

    WMI是Windows操作系统的一个核心组件,它提供了一种标准的方式来获取和操作系统的各种管理信息。在C#中,可以使用`System.Management`命名空间来访问WMI。以下是一个简单的示例,展示如何获取所有USB设备的设备ID:...

    获取U盘ID号

    USB(通用串行总线)是一种标准接口,允许外设如U盘、鼠标、键盘等与电脑通信。USB设备具有特定的设备类,例如存储设备类,U盘就属于这一类。每个USB设备都有一个独特的Vendor ID(供应商ID)和Product ID(产品ID)...

    nod32升级ID获取工具

    工具内含八条不同的线路,每条线路代表一种可能的ID获取途径,增加了获取成功的概率,确保了在各种网络环境下都能顺利获取到有效的升级ID。 首先,让我们了解一下为何需要升级ID。NOD32的数据库是动态更新的,新的...

    springboot分布式自增id_javaredis_源码

    3. **Redis的键过期策略**:Redis提供了两种过期策略,一种是定期检查,另一种是在读写操作时检查。当内存压力大时,Redis会触发淘汰策略,这里描述的是近似LRU策略。Redis并不是为每个键存储访问时间,而是使用一个...

    Hibernate继承映射的第一种策略:每个类对应一张表

    本文将详细探讨“Hibernate继承映射的第一种策略:每个类对应一张表”的概念、实现方式以及其优缺点。 首先,我们需要理解Hibernate继承映射的基本策略。在面向对象编程中,类继承是常见的代码复用手段,但在数据库...

    企业号获取idasdss

    在现代企业的信息化建设过程中,微信企业号作为一种高效的内部沟通与协作工具,被广泛应用。其中涉及到的功能之一就是通过微信企业号获取员工的用户ID,这对于后续实现更加精细化的企业内部管理和服务至关重要。 ##...

    Spring下使用策略模式

    在Spring框架中,策略模式是一种常见的设计模式,它允许我们定义一组可互换的策略,这些策略可以在运行时根据需求动态选择。这篇文章将深入探讨如何在Spring中运用策略模式,并结合源码分析其工作原理。 策略模式的...

    java快速ID自增器

    总结来说,"Java快速ID自增器"是一种解决在Java应用中生成唯一自增ID的策略。它可以是基于Java内置的原子类、数据库序列、分布式ID生成算法,或者是结合数据库和Spring框架的高级应用场景。选择哪种方案取决于具体的...

    电信设备-一种获取进程信息的方法及装置.zip

    文件“一种获取进程信息的方法及装置.pdf”很可能详细介绍了如何在特定的电信设备环境下实现这些功能,包括可能采用的特定技术和策略。 总的来说,理解和掌握获取进程信息的方法及装置对于电信设备的运维人员来说,...

    web取PC设备ID

    虽然它主要用于音频、视频通话,但其ICE(Interactive Connectivity Establishment)机制可能暴露内网IP,从而提供一种间接的设备标识。 综上所述,"web取PC设备ID"是一个涉及浏览器限制、隐私安全、硬件信息间接...

    JavaScript 获取计算机硬件信息

    在JavaScript中获取计算机硬件...总结,JavaScript获取计算机硬件信息的能力受到浏览器特性和安全策略的限制,而ActiveX和WMI是过去常用的一种方法,但随着技术的发展,这种方式逐渐被更安全、跨平台的解决方案所取代。

Global site tag (gtag.js) - Google Analytics