MySQL 5原子ID生成器

问题描述

| 我的逻辑需要在INSERT之前知道表的ID(在插入时手动设置ID)。因为使用该ID的逻辑在多个服务器上,所以让MysqL创建一个ID可能是一个好主意,但是我编写的函数不是原子的,因此在高负载调用它会返回一些相同的,不是唯一的数字:
CREATE FUNCTION `generate_document_log_id`() RETURNS BIGINT(16)
BEGIN
    DECLARE R_ID BIGINT(16);
    UPDATE document_log_sequence SET id = id + 1;
    SELECT id INTO R_ID FROM document_log_sequence;
    RETURN R_ID;
END
我正在使用带有“ id”列的表“ document_log_sequence \”来存储最后一个ID,并为每个新ID递增该ID。 也许解决方案远非如此,但是我没有更多的想法了。 我忘了解释: 只有一个数据库服务器和n个客户端。上面的功能不是线程安全的。     

解决方法

        您可以使用交错ID的策略 每个服务器从0到n编号,并将它们的服务器编号添加到以n为步长的序列中。一种实现是为ID生成一个
AUTO_INCREMENT
表,然后在如下函数中使用该ID:
CREATE TABLE ID_CREATOR (ID INT AUTO_INCREMENT PRIMARY KEY);
假设有3台服务器,并且该服务器是1号服务器,那么此函数将为每个服务器赋予唯一值:
CREATE FUNCTION generate_document_log_id() RETURNS INT
BEGIN
    DECLARE NUMBER_OF_SERVERS INT DEFAULT 3; -- Or read from some table
    DECLARE THIS_SERVER_ID INT DEFAULT 1; -- Or read from some table. Must be less than NUMBER_OF_SERVERS
    INSERT INTO ID_CREATOR VALUES (); -- This creates the next id
    RETURN LAST_INSERT_ID() * NUMBER_OF_SERVERS + THIS_SERVER_ID;  -- Unique numbers that interleave each other
END
    ,        仅供参考,如果您只有一个数据库服务器,这将为您提供要插入的下一个ID的值:
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_NAME = \'my_table\'
AND TABLE_SCHEMA = \'my_schema\';
(编辑-我误解了这个问题)     ,        有一些选择 1)您可以使用一个UUID,即一个16字节(128位)的密钥;此策略也适用于n个服务器数据库: 选择uuid(); (当然..您将需要一个字段CHAR(32)以纯文本存储您的UUID; MySQL暂时没有GUIID(128位)类型的字段) 我准备使用存储的函数,这是我的版本之一:
BEGIN
DECLARE str_uuid varchar(32);
DECLARE cur1 CURSOR FOR select replace (o.oid,\'-\',\'\') from (select lower(UUID()) as oid) as o;
open cur1;
fetch cur1 into str_uuid;
close cur1;
return str_uuid;
END
2)您可以使用INT或BIGINT,但是此策略仅适用于同一数据库服务器: 考虑具有字段my_last_id,dt_hr_id(my_last_id为AUTOINCREMENT)的表 启动一个隔离的连接,这样做 插入YourTable(dt_hr_id)值(NOW()); SELECT LAS_INSERT_ID(); (在这种情况下,SELECT始终有效,因为发生在所有者连接内) 关闭您的隔离连接; 这可以在存储过程/存储函数内部进行,但是您需要知道MySQL在同一连接中不支持多个事务,因此您需要在隔离连接中进行。