从数据库中批量(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; } }
。。。
相关推荐
它的作用是提供一种系统性的方法,以有效地应对挑战、优化流程或实现目标。以下是方案的主要作用: 问题解决: 方案的核心目标是解决问题。通过系统性的规划和执行,方案能够分析问题的根本原因,提供可行的解决...
11. 插件式的自定义Cookie策略。 12. Request的输出流可以避免流中内容直接缓冲到socket服务器。 13. Response的输入流可以有效的从socket服务器直接读取相应内容。 14. 在http1.0和http1.1中利用KeepAlive保持持久...
1.hibernate提供的更面向对象的一种查询方式。 准备工作: 1.java中的POJO对象存在 2.数据库,表得存在 3.hibernate的配置文件(hibernate.cfg.xml)得存在 4.POJO.hbm.xml文件存在 5.hibernate的jar包以及数据库的...
一、Android中的缓存策略 一般来说,缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存还是硬盘缓存,它们的缓存大小都是...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
要解决这个问题,可以采用两种策略:一是自动刷新token,二是token续约。通过在验证用户权限的同时为用户生成新的token并返回给客户端,可以确保客户端及时更新本地存储的token。此外,设置定时任务来刷新token也是...
提出并实现了一种建立在Peer-to-Peer搜索策略上的自组织、自适应、高效和可靠的文件系统DISPFS(Double ID Space based Peer-to-Deer File System)。它在双层ID空间中构造虚拟存储节点,不仅有效地取得了文件系统内的...
这种策略支持双向的一对多关联,但不支持 IDENTIFY 生成器策略,因为ID必须在多个表间共享。一旦使用就不能使用AUTO和IDENTIFY生成器。 每个类层次结构一张表 @Entity @Inheritance(strategy=InheritanceType....
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
WebAPI-Nodejs是一种API中间件,用于管理有关保险单和公司客户的某些信息。 入门 该API允许您执行以下操作: 使用用户电子邮件登录->您将获得令牌,只要您获得角色授权,便可以获取所有请求。 获取按用户ID过滤的...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
在这里稍微变化下,就是允许所有请求都能够创建成功,但是得有个创建顺序,于是所有的请求最终在ZK上创建结果的一种可能情况是这样: /currentMaster/{sessionId}-1 ,/currentMaster/{sessionId}-2,/currentMaster/{...
读取手机状态和身份,用于获取设备的唯一标识,为当前设备生成一个唯一设备ID。 查看Wifi状态权限,用于获取mac地址,生成设备唯一标示。 获取用户地理位置信息,用于获取精准确的地理位置,变于统计用户分布情况。...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。 爬虫的...
一种策略是采用Linux所做的事情,并使用位图,其中位置i处的值为0表示值i的进程ID可用,值1表示当前正在使用的进程ID。 实现以下API,以获取和释放pid: •intallocate_map(void)–创建并初始化用于表示pid的...
作为一种让人们浏览来自外部用户的消息的方法, 插件用于从服务器获取线程。 UI用vue.js编写,可以显示帖子和有关消息的自定义配置文件。 起作用的东西: 部分复制 使用与其他同伴直接连接 查看帖子和主题,包括...
另外有时还会遇到另外一种情况:访问XP的时候,登录对话框中的用户名是灰的,始终是Guest用户,不能输入别的用户帐号。 解决:本地策略 -> 安全选项 -> "网络访问:本地帐户的共享和安全模式",修改为"经典-本地用户...
* 其十三种策略(strategy属性的值)如下: * 1.native 对于orcale采用Sequence方式,对于MySQL和SQL Server采用identity(处境主键生成机制), * native就是将主键的生成工作将由数据库完成,hibernate不管(很常用...