唯一主键方案之数据库维护区间分配

Posted JMCui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了唯一主键方案之数据库维护区间分配相关的知识,希望对你有一定的参考价值。

我们介绍一种基于数据库维护自增 ID 区间,结合内存分配的策略,这也是淘宝的 TDDL 等数据库中间件使用的主键生成策略。

使用这种方式首先在数据库中创建 sequence 表,其中的每一行,用于记录某个业务主键当前已经被占用的 ID 区间的最大值。sequence 表的主要字段是 name 和 value,其中 name 是当前业务序列的名称,value 存储已经分配出去的 ID 最大值。

CREATE TABLE `sequence_global` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT \'Id\',
  `app_name` varchar(64) NOT NULL COMMENT \'sequence name\',
  `app_value` bigint(32) NOT NULL COMMENT \'sequence current value\',
   `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT \'创建时间\',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT \'修改时间\',
   PRIMARY KEY (`id`),
  UNIQUE KEY `unique_name` (`app_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

接下来插入一条行记录,当需要获取主键时,每台服务器主机从数据表中取对应的 ID 区间缓存在本地,同时更新 sequence 表中的 value 最大值记录。

现在我们新建一条记录,比如设置一条 order 更新的规则,插入一行记录如下:

INSERT INTO sequence_global(app_name,app_value,create_time,update_time) values(\'test\',200,now(),now());

当服务器在获取主键增长区段时,首先访问对应数据库的 sequence 表,更新对应的记录,占用一个对应的区间。比如我们这里设置步长为 200,原先的 value 值为 1000,更新后的 value 就变为了 1200。

取到对应的 ID 区间后,在服务器内部进行分配,涉及的并发问题可以依赖乐观锁等机制解决。

有了对应的 ID 增长区间,在本地就可以使用 AtomicInteger 等方式进行 ID 分配。

不同的机器在相同时间内分配出去的 ID 可能不同,这种方式生成的唯一 ID,不保证严格的时间序递增,但是可以保证整体的趋势递增,在实际生产中有比较多的应用。

为了防止单点故障,sequence 表所在的数据库,通常会配置多个从库,实现高可用。

参考代码实现:https://github.com/JMCuixy/dubbo-demo/tree/master/sequence

以上是关于唯一主键方案之数据库维护区间分配的主要内容,如果未能解决你的问题,请参考以下文章

SQL中的外部键约束有啥用?

主键唯一约束混淆/解决方案

我爱java系列之---分布式ID生成解决方案:UUIDRedis生成idsnowflake

大家一起撸代码之——Hibernate各种主键生成策略与配置详解

SQL入门经典之键和约束

hdu 5654 xiaoxin and his watermelon candy 树状数组维护区间唯一元组