MySQL:基于带有事务的多列PK自动递增

时间:2015-01-02 20:15:16

标签: mysql triggers auto-increment

我有这种结构的表格:

CREATE TABLE IF NOT EXISTS `message` (
  `id` bigint(20) NOT NULL,
  `appKey` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `text` text COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

和主键(idappKey

我想独立地为每个appKey添加id自动增量。所以我使用触发器。

CREATE TRIGGER `messageId` BEFORE INSERT ON `message`
 FOR EACH ROW begin
    declare v_messageId bigint(20) unsigned default 0;
    SELECT max(id) INTO v_messageId FROM message WHERE appKey = new.appKey;
    if (v_messageId IS NULL) THEN
        set v_messageId=0;
    end if;
    SET new.id=v_messageId + 1;
end

它工作正常,直到我试图从两个数据库连接(我在应用程序中使用连接池)同时插入两行。插入第一行。但是第二次抛出错误ER_DUP_ENTRY:为'PRIMARY'键重复输入'18 -secretkey'。

我知道为什么会这样。我的问题是:MySQL是否有可能完成这项任务,或者我必须使用不同的数据库(可能因为咨询锁定而导致PostgreSQL)?

修改

在表格中我有这些行:

id | appKey | text
---+--------+-----------
 1 | key 1  | something
 2 | key 1  | something
 1 | key 2  | something
 2 | key 2  | something
 3 | key 1  | something

错误发生在我尝试插入这两行之后:

appKey | text
-------+-------
 key1  | something
 key1  | something

1 个答案:

答案 0 :(得分:1)

就我个人而言,我强烈建议您不要自行管理ID。这样做没有商业价值。

现在,如果你想坚持使用它,出于某种原因,至少要使用LAST_INSERT_ID(expr)。它是在MySQL中生成序列的唯一多用户安全方式。此外,您还需要额外的表来存储每个appKey的序列。

CREATE TABLE message_seq (
  appKey VARCHAR(64) NOT NULL PRIMARY KEY,
  seq BIGINT(20) NOT NULL
);

您的触发器将如下所示

DELIMITER //
CREATE TRIGGER `messageId` 
BEFORE INSERT ON `message`
FOR EACH ROW 
BEGIN
  INSERT INTO message_seq(appkey, seq) VALUES (NEW.appKey, LAST_INSERT_ID(1)) 
  ON DUPLICATE KEY UPDATE seq = LAST_INSERT_ID(seq + 1);    
  SET NEW.id = LAST_INSERT_ID();
END//
DELIMITER ;

这是 SQLFiddle 演示

进一步阅读: