我有这种结构的表格:
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自动增量。所以我使用触发器。
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
答案 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 演示
进一步阅读: