MySQL中的触发器和表锁

MySQL中的触发器和表锁,mysql,concurrency,triggers,locking,Mysql,Concurrency,Triggers,Locking,场景:我有一些触发器可以跟踪一个表的记录数以及其他有用的信息。在该表上添加/删除/更新时触发这些触发器,并负责将这些信息写入另一个补充表中 现在,这些触发器将在多线程环境中运行,在这个环境中,我可能会同时访问表。 我希望我能做这样的事情,但这是禁止的(错误:错误代码:1314。存储过程中不允许使用锁): 使用这些锁(或替代构造)要实现的目标是: 避免同时运行两个触发器写入AlarmCount表并更新相关记录(我想可能有两个触发器针对不同的报警表记录运行,以更新相同的AlarmCount记录) 确

场景:我有一些触发器可以跟踪一个表的记录数以及其他有用的信息。在该表上添加/删除/更新时触发这些触发器,并负责将这些信息写入另一个补充表中

现在,这些触发器将在多线程环境中运行,在这个环境中,我可能会同时访问表。 我希望我能做这样的事情,但这是禁止的(错误:错误代码:1314。存储过程中不允许使用锁)

使用这些锁(或替代构造)要实现的目标是:

  • 避免同时运行两个触发器写入AlarmCount表并更新相关记录(我想可能有两个触发器针对不同的报警表记录运行,以更新相同的AlarmCount记录)
  • 确保不会同时修改AlarmMembership表(例如,同时删除目标MemberId)

  • 欢迎任何意见

    我认为处理这个问题的最好方法是使用SELECT。。。对于此处描述的更新模式:

    供参考:

    让我们看另一个例子:在 表child_代码,用于为每个表分配唯一标识符 添加到表child的child。使用这两种方法都不是一个好主意 一致读取或共享模式读取,以读取 计数器,因为数据库的两个用户可能会看到相同的值 对于计数器,如果两个用户尝试 将具有相同标识符的子项添加到表中

    在这里,锁定共享模式不是一个好的解决方案,因为如果两个用户 同时读取计数器,其中至少有一个以 尝试更新计数器时出现死锁

    要实现计数器的读取和递增,首先执行 锁定用于更新的计数器的读取,然后增加 柜台例如:

    精选的。。。对于更新,读取最新的可用数据,在其读取的每行>上设置排他锁。因此,它设置的锁与搜索到的SQL更新在行上设置的锁相同

    。 .

    注意:仅适用于使用SELECT for update锁定要更新的行 禁用自动提交时(通过以下方式开始事务) 启动事务或将“自动提交”设置为0。如果“自动提交”为 启用时,与规范匹配的行未锁定

    所以在你的情况下,你会替换

    LOCK TABLES AlarmCount WRITE, AlarmMembership READ;
      UPDATE AlarmCount SET num = num - 1 
      WHERE RuleId = OLD.RuleId AND
          MemberId = 0 AND
          IsResolved = OLD.IsResolved;
    
    有点像

    SELECT num FROM AlarmCount WHERE RuleId = OLD.RuleId AND
              MemberId = 0 AND
              IsResolved = OLD.IsResolved FOR UPDATE;
    UPDATE AlarmCount SET num = num - 1;
    
    我之所以说“类似”,是因为我不完全清楚OLD.RuleId和OLD.IsResolved是指什么。另外值得注意的是:

    前面的描述只是一个如何选择…的示例 在MySQL中,生成唯一 实际上,只需一次访问就可以实现标识符 下表:

    SELECT语句仅检索标识符信息(特定于当前 连接)。它不访问任何表

    换句话说,您可能只需要访问一次表就可以进一步优化此模式……但是,关于您的模式,我仍然不太了解其中的一些细节,我不确定是否可以提供您需要的实际语句。我确实认为,如果您查看一下SELECT…以获取更新,您将看到模式的最终内容以及您需要做些什么才能使其在您的环境中工作

    <>我也应该提到,有一些存储引擎环境和事务隔离级别,您将需要考虑。这里有一个非常非常好的关于这个主题的讨论:


    希望这有帮助!

    我最终锁定了调用方代码,从而防止了潜在的冲突。但是,非常好的解决方案谢谢!下次我有同样的问题我会考虑这一点。当试图用“选择更新”锁定表时,我“不允许从触发器返回结果集”。
    LOCK TABLES AlarmCount WRITE, AlarmMembership READ;
      UPDATE AlarmCount SET num = num - 1 
      WHERE RuleId = OLD.RuleId AND
          MemberId = 0 AND
          IsResolved = OLD.IsResolved;
    
    SELECT num FROM AlarmCount WHERE RuleId = OLD.RuleId AND
              MemberId = 0 AND
              IsResolved = OLD.IsResolved FOR UPDATE;
    UPDATE AlarmCount SET num = num - 1;
    
    UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field +
    1); 
    SELECT LAST_INSERT_ID();