获取id 的一种策略

来源:互联网 发布:下载哈萨克dombira软件 编辑:程序博客网 时间:2024/05/22 06:41

从数据库中批量(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;}}

 。。。

 

 

 

 

 

 

原创粉丝点击