【问题标题】:Getting id generated in a trigger for further requests获取在触发器中生成的 id 以获取更多请求
【发布时间】:2020-08-17 10:45:22
【问题描述】:

我有一个包含两列的表格:

  • caseId,引用外部表列
  • caseEventId, int, unique 用于给定的 caseId,我想为同一 caseId 自动递增

我知道基于另一列的自动增量选项在 mySql 中与 InnoDb 不可用:

MySQL Auto Increment Based on Foreign Key

MySQL second auto increment field based on foreign key

所以我将 caseEventId 生成到触发器中。我的桌子:

CREATE TABLE IF NOT EXISTS mydb.caseEvent (
  `caseId` CHAR(20) NOT NULL,
  `caseEventId` INT NOT NULL DEFAULT 0,
  PRIMARY KEY (`caseId`, `caseEventId`),
  # Foreign key definition, not important here.
ENGINE = InnoDB;

还有我的触发器:

CREATE DEFINER=`root`@`%` TRIGGER `mydb`.`caseEvent_BEFORE_INSERT` BEFORE INSERT ON `caseEvent` FOR EACH ROW
BEGIN
    SELECT COALESCE((SELECT MAX(caseEventId) + 1 FROM caseEvent WHERE caseId = NEW.caseId),0)
        INTO @newCaseEventId;
    SET NEW.`caseEventId` = @newCaseEventId;
END

有了这个,我得到了自动递增的 caseEventId。

但是,我需要在我的 INSERT 事务中的进一步调用中重新使用这个新的 caseEventId,所以我将此 id 放入触发器中的 @newCaseEventId 中,并在以下说明中使用它:

START TRANSACTION;
INSERT INTO mydb.caseEvent (caseId) VALUES ('fziNw6muQ20VGYwYPW1b');
SELECT @newCaseEventId;
# Do stuff based on @newCaseEventId
COMMIT;

这似乎工作得很好但是......并发,使用连接池等......?

此@newCaseEventId 变量是否将与使用同一连接的所有客户端共享,当我的客户端服务器启动两个并发事务时我会遇到问题吗?这是在nodejs下使用mysql。

这是安全的,还是有更安全的方法来解决这个问题?谢谢。


编辑 2020/09/24

仅供参考,我完全放弃了这种方法。我试图以不适合使用的方式使用数据库。

基本上我已经删除了 caseEventId,以及任何应该根据给定列值很好地递增的索引。

当我检索数据时,我依靠读取端正确编写的查询来重新创建我的 caseEventId 字段...

【问题讨论】:

  • 您通过这样做创建了一个竞争条件。换句话说,如果两个并发会话同时 INSERT 会怎样?它们都将为max(caseEventId)+1 读取相同的值。最终,除了锁定表之外,您无法实现每个 caseId 的自动增量。
  • @Bill Karwin 这部分是我担心的。如果您有关于如何在不产生潜在死锁的情况下实现表锁的指南,我很感兴趣!
  • LOCK TABLES 会这样做。大多数人会避免这种情况,因为如果您的应用程序需要在表上同时执行高速率的查询,它会严重限制吞吐量。但是,如果您的查询率较低,它可以工作。
  • 另一个更常见的解决方案是忘记为每个 caseId 独立编号你的 caseEvent。只需使用自动增量。

标签: mysql node.js innodb


【解决方案1】:

没问题,用户为每个客户端定义一个变量。

这意味着每个用户都有自己使用定义的变量

用户定义的变量是特定于会话的。一个客户端定义的用户变量不能被其他客户端看到或使用。 (例外:有权访问性能模式 user_variables_by_thread 表的用户可以查看所有会话的所有用户变量。)给定客户端会话的所有变量都会在该客户端退出时自动释放。 see manul

【讨论】:

  • 我的客户端是 nodejs / express 服务器。它将并行处理多个请求,并启动并发的 mySql 查询。这些查询来自同一个服务器,它们会被认为来自同一个客户端吗?我仍然不清楚如何处理连接。
  • 你必须在某个地方有一个连接,然后你关闭那个连接(我希望)或者你有一个连接并通过那里发送所有请求?
  • 是的,我为每笔交易打开和关闭连接,所以根据您的反应,我想我没问题。然后剩下的是 Bill Karwin 的评论,以及锁定表以避免竞争条件的需要。谢谢!
  • 是的,锁定表是一种可能,因为列 UNIQUE 是另一种。有一个很好的理由,为什么 auto_increment 在 mysql 中存在并且可以工作,在你的应用程序操作系统中做这一切,如果你只需要不必要的数字。
猜你喜欢
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
  • 2018-08-24
  • 2013-07-08
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
相关资源
最近更新 更多