基于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>