MySQL:基于事务的多列PK自增

MySQL: Auto-increment based on multi-column PK with transaction

我有table这个结构:

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;

和主键 (id,appKey)

我想为每个 appKey 单独设置 id autoincrement。所以我用触发器。

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,因为咨询锁)?

编辑:

在 table 我有这样的行:

编号 |应用密钥 |文本
---+--------+------------
 1 |键 1 |某物
 2 |键 1 |某物
 1 |键 2 |某物
 2 |键 2 |某物
 3 |键 1 |某物

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

应用密钥 |文本
------+--------
 键1 |某物
 键1 |某物

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

如果出于某种原因你想坚持下去,至少要使用 LAST_INSERT_ID(expr)。这是 在 MySQL 中唯一的 多用户安全生成序列的方法。此外,您还需要额外的 table 来存储每个 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演示

进一步阅读: