首页 编程 软件学院 查看内容

获取id 的一种策略

2015-7-8 11:35 1878 0

摘要: 从数据库中批量(step个)拿出Id,然后使用,待消耗完后再批量拿出Idkey1 = genKey+"##"+subKey;三个并发Map:mapLock:判断是否存在锁mapGenId:保存每次的currNo值mapMaxId:保存每次currNo+step后的值三个Concu ...
关键词: subKey genKey currNo String genIdVo cdoRequest long return GenIdHelper static

从数据库中批量(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 mapLock = new ConcurrentHashMap();
  
  //每个记录的步长
  private static ConcurrentHashMap mapStep = new ConcurrentHashMap();
  
  //每个记录的ID值
  private static ConcurrentHashMap mapGenId = new ConcurrentHashMap();
  
  //每个记录的MAXID值
  private static ConcurrentHashMap mapMaxId = new ConcurrentHashMap();
  
  /*
   * 懒汉,线程安全
   */
  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;
    
  }

}
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部