获取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;
}
}
。。。
已有 0 人发表留言,猛击->> 这里<<-参与讨论
ITeye推荐