MySQL 5原子id生成器

时间:2011-06-14 13:12:14

标签: mysql id-generation

我的逻辑需要在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增加它。 也许解决方案远非如此,但我没有更多的想法。

我忘了解释: 只有一个数据库服务器和n个客户端。上面的函数不是(种类)线程安全的。

3 个答案:

答案 0 :(得分:1)

仅供参考,如果您只有一个数据库服务器,这将为您提供要插入的下一个ID的值:

SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_NAME = 'my_table'
AND TABLE_SCHEMA = 'my_schema';

(编辑 - 我误解了这个问题)

答案 1 :(得分:1)

您可以使用 interleaved ID

的策略

每个服务器的编号为0到n,并将其服务器编号添加到以n为单位的序列中。一个实现是使用AUTO_INCREMENT表生成id,然后在这样的函数中使用该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

答案 2 :(得分:0)

有一些选项

1)您可以使用一个UUID,一个16字节(128位)的密钥;这个策略也适用于n个服务器数据库:

选择uuid(); (当然..你需要一个字段CHAR(32)来存储你的UUID在纯文本; MySQL没有字段os类型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)的表 启动一个独立的连接,所以

  • INSERT INTO YourTable(dt_hr_id)值(NOW());
  • SELECT LAS_INSERT_ID(); (在这种情况下,SELECT总是有效,因为在所有者连接中发生)

关闭您的隔离连接;

这可以在存储过程/存储函数中执行,但您需要知道MySQL不支持同一连接中的多个事务,因此您需要在隔离连接中执行此操作。