一种简单的ID生成策略: Mysql表生成全局唯一ID

生成全局ID的方法很多, 这里记录下一种简单的方案: 利用mysql的自增id生成全局唯一ID.

1. 创建一张只需要两个字段的表:

CREATE TABLE `guid` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `stub` char(1) NOT NULL DEFAULT '' COMMENT '桩字段,占坑的',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_stub` (`stub`)  -- 将 stub 设为唯一索引
) ENGINE=MyISAM AUTO_INCREMENT=1000000000 DEFAULT CHARSET=utf8; 

指定自增起始: alter table guid auto_increment=1000000000, 这样可以保证ID为10位(涨到11位几乎不可能吧).

2. 定义 mybatis mapper:

@Mapper
public interface GuidMapper {


    /**获取全局唯一ID
     * @return
     */
    // replace into afs_guid(stub) values('a');
    // select last_insert_id();
    @Insert("REPLACE INTO guid (stub) VALUES('a')")
    @SelectKey(statement = {"SELECT LAST_INSERT_ID()"}, keyProperty = "guidHolder.id", before = false, resultType = long.class)
    int getGuid( @Param("guidHolder") GuidHolder guidHolder);

    @Data
    public static class GuidHolder{
        private long id;
        private String stub;
    }

3. 测试

 GuidMapper.GuidHolder guidHolder = new GuidMapper.GuidHolder();
 int i = guidMapper.getGuid(guidHolder);
 long                  guid         = guidHolder.getId();
 // guid 就是返回的ID

尾巴

并发安全问题

  1. REPLACE INTO 类似于 INSERT 是安全的. 不只是它会先判断主键或唯一键是否重复, 重复, 则删除原有的, 新增一条, 替换原来的.
  2. SELECT LAST_INSERT_ID() 是和mysql连接绑定的, 当前连接上, 操作触发了auto_increment值改变, 得到新的数值, 这个数值, 只会被当前连接可见. 其他连接也只会拿到它改变auto_increment后的值.

以上两点保证了 并发安全 .

另外, 即使手动将id的值改小了, 下次 replace into 后依然会从上次自增的基础上继续自增. 因为手动修改id的值, 不会改变auto_increment的值.

你可能感兴趣的:(java)