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演示
进一步阅读:
我有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演示
进一步阅读: