基于DB的全局唯一id

基于DB的全局唯一id

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

代码如下

/**
 * 内部id生成器
 * Created by carey on 2017/5/26.
 */
@Component
public class InnerIdemIdGen {

    private Map 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>

你可能感兴趣的:(分布式)