基于DB的全局唯一id

时间:2022-09-23 11:40:35

基于DB的全局唯一id

同一个jvm内使用atomicLong保证,非同一个jvm内使用db的乐观锁保证。
当id超过设置的最大值后,自动归零复位。
格式为yymmdd+ 业务码 + id

代码如下

/**
* 内部id生成器
* Created by carey on 2017/5/26.
*/

@Component
public class InnerIdemIdGen {

private Map<InnerBusinessEnum, IdGenerator> bizGenCache = new HashMap<>();

private Logger logger = LoggerFactory.getLogger("biz");
/**
* id步长控制
*/

private final long StepSize = 200;

/**
* 最大的步长,10?的格式
*/

private final long MaxCount = 1000000;

@Resource
private IdGenMapper idGenMapper;

/**
* 初始化,从db加载
*/

@PostConstruct
private void init() {
for (InnerBusinessEnum innerBusinessEnum : InnerBusinessEnum.values()) {
IdGenerator idGenerator = new IdGenerator(innerBusinessEnum.getName());
idGenerator.init();
bizGenCache.put(innerBusinessEnum, idGenerator);
}
logger.info("主键生成器注册完成");
}

/**
* 生成全局幂等id
* yymmdd + bizcode(3位) + 6位id
* @param innerBusinessEnum 内部定义的业务线
* @return
*/

public long gen(InnerBusinessEnum innerBusinessEnum) {
IdGenerator idGenerator = bizGenCache.get(innerBusinessEnum);
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
String time = sdf.format(new Date()).concat(innerBusinessEnum.getCode());

return Long.valueOf(time) * MaxCount + idGenerator.next();
}


/**
* 生成器
* 同jvm内使用atomic保证
* 非jvm内使用乐观锁保证
*/

private class IdGenerator {
/**
* 表中的名字
*/

private String key;
private AtomicLong count = new AtomicLong();
/**
* 下一次的天花板 需要重新从db中获取
*/

private volatile long nextGenTop;

IdGenerator(String key) {
this.key = key;
}

/**
* 使用乐观锁
*/

private void init() {
int changeSize;
long curCount;
do {
curCount = idGenMapper.getIndex(key);
changeSize = idGenMapper.updateIndex(key, curCount, StepSize);
} while (changeSize != 1);
count.set(curCount);
nextGenTop = curCount + StepSize;
}

/**
* 获取下一个id
* @return
*/

private long next() {
long curCount = count.incrementAndGet();
if (curCount <= nextGenTop) {
return curCount;
}
synchronized (count) {
curCount = count.incrementAndGet();
if (curCount < nextGenTop) {
return curCount;
}
init();
curCount = count.incrementAndGet();
if (curCount > MaxCount) {
reset(nextGenTop);
return count.incrementAndGet();
}
return curCount;


}
}

/**
* id达到了上限, 复位
* @param topCount
*/

private void reset(long topCount) {
int changeSize = idGenMapper.reset(key, topCount);
if (0 == changeSize) {
init();
} else {
nextGenTop = StepSize;
count.set(0);
}

}
}


public enum InnerBusinessEnum {
PICC_ID("picc", "001"),
Test("test", "002");

/**
* 表中的名字
*/

private String name;

/**
* 业务标识码
* yymmdd + bizCode + id
*/

private String code;

private InnerBusinessEnum(String name, String code) {
this.name = name;
this.code = code;
}

public String getName() {
return name;
}

public String getCode() {
return code;
}
}
}

db的部分


<select id="getIndex" resultType="java.lang.Long">
select cur_count from cop_id_gen where biz_key = '${key}';

</select>

<update id="updateIndex">
update cop_id_gen set cur_count = cur_count + ${stepSize} WHERE biz_key = '${key}' and cur_count = ${cur_count};
</update>


<update id="reset">
update cop_id_gen set cur_count = 0 WHERE biz_key = '${key}' and cur_count = ${cur_count};


</update>