`
uule
  • 浏览: 6303331 次
  • 性别: 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
分享到:
评论

相关推荐

    一种Android客户端获取唯一设备ID的方案.zip

    它的作用是提供一种系统性的方法,以有效地应对挑战、优化流程或实现目标。以下是方案的主要作用: 问题解决: 方案的核心目标是解决问题。通过系统性的规划和执行,方案能够分析问题的根本原因,提供可行的解决...

    HttpClient以及获取页面内容应用

    11. 插件式的自定义Cookie策略。 12. Request的输出流可以避免流中内容直接缓冲到socket服务器。 13. Response的输入流可以有效的从socket服务器直接读取相应内容。 14. 在http1.0和http1.1中利用KeepAlive保持持久...

    jdbc基础和参考

    1.hibernate提供的更面向对象的一种查询方式。 准备工作: 1.java中的POJO对象存在 2.数据库,表得存在 3.hibernate的配置文件(hibernate.cfg.xml)得存在 4.POJO.hbm.xml文件存在 5.hibernate的jar包以及数据库的...

    浅谈Android LruCache的缓存策略

    一、Android中的缓存策略 一般来说,缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存还是硬盘缓存,它们的缓存大小都是...

    java写的爬虫程序,可以根据商品id爬取排名,生成excel.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    Java如何做到无感知刷新token含示例代码(值得珍藏)

    要解决这个问题,可以采用两种策略:一是自动刷新token,二是token续约。通过在验证用户权限的同时为用户生成新的token并返回给客户端,可以确保客户端及时更新本地存储的token。此外,设置定时任务来刷新token也是...

    基于双层ID空间的Peer-to-Peer文件系统设计与实现 (2005年)

    提出并实现了一种建立在Peer-to-Peer搜索策略上的自组织、自适应、高效和可靠的文件系统DISPFS(Double ID Space based Peer-to-Deer File System)。它在双层ID空间中构造虚拟存储节点,不仅有效地取得了文件系统内的...

    Hibernate注释大全收藏

    这种策略支持双向的一对多关联,但不支持 IDENTIFY 生成器策略,因为ID必须在多个表间共享。一旦使用就不能使用AUTO和IDENTIFY生成器。 每个类层次结构一张表 @Entity @Inheritance(strategy=InheritanceType....

    淘宝爬虫.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    WebAPI-Nodejs

    WebAPI-Nodejs是一种API中间件,用于管理有关保险单和公司客户的某些信息。 入门 该API允许您执行以下操作: 使用用户电子邮件登录-&gt;您将获得令牌,只要您获得角色授权,便可以获取所有请求。 获取按用户ID过滤的...

    爬虫爬取懂车帝目标地区的所有汽油车信息.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    Bilibili视频数据爬虫 精确爬取完整的b站视频数据.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    分布式协调工具-ZooKeeper实现动态负载均衡

    在这里稍微变化下,就是允许所有请求都能够创建成功,但是得有个创建顺序,于是所有的请求最终在ZK上创建结果的一种可能情况是这样: /currentMaster/{sessionId}-1 ,/currentMaster/{sessionId}-2,/currentMaster/{...

    自定义统计SDKTcStatInterface.zip

    读取手机状态和身份,用于获取设备的唯一标识,为当前设备生成一个唯一设备ID。 查看Wifi状态权限,用于获取mac地址,生成设备唯一标示。 获取用户地理位置信息,用于获取精准确的地理位置,变于统计用户分布情况。...

    停车场系统源码,新能源充电桩系统,停车场小程序,智能停车,Parking system.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    停车场系统源码,停车场小程序,智能停车,Parking system.zip

    爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...

    操作系统

    一种策略是采用Linux所做的事情,并使用位图,其中位置i处的值为0表示值i的进程ID可用,值1表示当前正在使用的进程ID。 实现以下API,以获取和释放pid: •intallocate_map(void)–创建并初始化用于表示pid的...

    ssb-browser-demo:在浏览器中运行的安全的scuttlebutt客户端界面

    作为一种让人们浏览来自外部用户的消息的方法, 插件用于从服务器获取线程。 UI用vue.js编写,可以显示帖子和有关消息的自定义配置文件。 起作用的东西: 部分复制 使用与其他同伴直接连接 查看帖子和主题,包括...

    您可能没有权限使用网络资源。请与这台服务器的管理员联系以查明您是否有访问权限。拒绝访问解决方法

    另外有时还会遇到另外一种情况:访问XP的时候,登录对话框中的用户名是灰的,始终是Guest用户,不能输入别的用户帐号。 解决:本地策略 -&gt; 安全选项 -&gt; "网络访问:本地帐户的共享和安全模式",修改为"经典-本地用户...

    Hibernate注解

    * 其十三种策略(strategy属性的值)如下: * 1.native 对于orcale采用Sequence方式,对于MySQL和SQL Server采用identity(处境主键生成机制), * native就是将主键的生成工作将由数据库完成,hibernate不管(很常用...

Global site tag (gtag.js) - Google Analytics