【问题标题】:MySQL: Auto-increment based on multi-column PK with transactionMySQL:基于事务的多列 PK 的自动增量
【发布时间】:2015-03-01 03:07:44
【问题描述】:

我有这种结构的表:

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: Duplicate entry '18-secretkey' for key 'PRIMARY'。

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

编辑:

在表中我有这些行:

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

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

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

【问题讨论】:

  • dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html 使用内置工具。使用 max(ID) 加 1 对竞态条件的异常处理非常令人头疼
  • @xBert 我猜你不明白我的问题。我编辑了问题。
  • 从上面的链接,“MyISAM 注释 对于 MyISAM 表,您可以在多列索引中的辅助列上指定 AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT 列的生成值计算为 MAX( auto_increment_column) + 1 WHERE prefix=given-prefix。当您想将数据放入有序组时,这很有用。如果这不是你想要做的,我真的不明白你的问题。
  • @xQbert 我正在使用 InnoDB 引擎,无法使用 MyISAM。这就是我尝试使用触发器解决此问题的原因。
  • 不知道为什么我错过了那个语法... sorr.y

标签: mysql triggers auto-increment


【解决方案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演示

进一步阅读:

【讨论】:

    猜你喜欢
    • 2020-03-09
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多