【问题标题】:MySQL - Lock tables or begin transaction from a triggerMySQL - 锁定表或从触发器开始事务
【发布时间】:2014-01-24 07:08:39
【问题描述】:

在高层次上,我所拥有的是:

  1. 由应用程序 1 填充和管理的“主”数据库。
  2. 使用standard mechanism 从“主”数据库复制的单独主机上的“从”数据库。
  3. 应用程序 2,独立于应用程序 1 运行,对从属数据库的只读访问权限和对其自己独立数据库的读写访问权限非常有限。

基本上需要发生的是,当“从属”数据库中的某些事情发生变化时,应用程序 2 需要得到通知,以便它可以检查“从属”数据库的内容并将一些内容写入自己的数据库。

性能不是问题,发生这种情况时锁定整个“从属”数据库是可以接受的。 关键是要确保在应用程序 2 完成操作之前不会将更多信息复制到“从属”数据库中。应用程序 2 从独立于触发的会话访问“从属”数据库通知。

为此,我有以下触发器

delimiter //
CREATE TRIGGER create_report_trigger AFTER UPDATE ON jobs
        FOR EACH ROW 
                BEGIN
                        DECLARE report_id INT;
                        IF (NEW.status = 7 AND OLD.status != 7) THEN
                                CALL CREATE_REPORT_PROC(NEW.id, @report_id);
                        END IF;
                END;
        //
delimiter ;

...由于您无法从触发器中启动事务或锁定数据库,因此我还有以下过程

delimiter //
CREATE PROCEDURE create_report_proc( 
        IN jobId INT,
        OUT report_id INT 
)
        BEGIN
                START TRANSACTION WITH CONSISTENT SNAPSHOT;
                SELECT CREATE_REPORT(jobId) INTO report_id;
                COMMIT;
        END //
delimiter ;

该过程正在调用user-defined function,它使用 libcurl 联系应用程序 2 并让它知道它需要处理该作业。

当我在 MySQL 命令行上手动调用它时,该过程运行良好。但是,当它从触发器中调用时,MySQL 日志中会出现以下错误:

Explicit or implicit commit is not allowed in stored function or trigger

...显然 MySQL 足够聪明,可以检测到我试图通过将触发器委托给过程来破坏其“不从触发器内部锁定”规则。

用户定义函数在将结果返回给其调用者之前等待应用程序 2 的操作完成,这可能是相关的(如果 MySQL 复制过程基本上被触发器执行阻塞,则无需手动锁定任何内容; 复制过程是唯一能够对“从”数据库进行更改的东西。

无论如何,我想这里有两个问题:

  1. 既然触发器是由于 MySQL 复制进程进行更新而触发的,这是否意味着在触发器返回之前复制进程被阻塞?

  2. 如果没有,我如何锁定数据库或以其他方式从触发器停止复制过程?我想从触发器内部发出STOP SLAVE; 可能会做到这一点?

编辑 - 这是一个额外的后续问题:

当应用程序 2 去做它的事情时,它看到的数据并没有反映应该在“从”数据库中的最新信息。具体来说,作为触发事务的一部分对jobs 表所做的任何更新对应用程序 2 都是不可见的。

既然触发器配置为触发AFTER UPDATE,为什么会出现这种情况?是否有任何方法可以使数据库中的应用程序 2 可以看到新内容,或者是否有必要手动收集并传递所有更新的字段值作为发送通知的一部分?

【问题讨论】:

    标签: mysql stored-procedures triggers database-replication


    【解决方案1】:

    好的,根据我自己的研究:

    1. 触发器执行是同步的,并阻塞调用线程,直到触发器完成。默认情况下,MySQL 复制本质上是一个单线程进程(我认为即使启用多线程复制,每个数据库也只能获得一个线程)。因此,在我的情况下,出于所有实际目的阻止复制线程“锁定”数据库;除了复制线程之外没有其他人有写权限。

    2. 你没有,明确的。但是,触发器的执行被认为是触发它的事务的一部分,这意味着您可能无论如何都被隐式锁定/处于原子事务中。这种情况发生的程度似乎取决于您的存储引擎和事务隔离设置。

    3. 仍然不完全确定“奖金”问题,但我推测它与 #2 有关。如果触发器执行是触发它的事务的一部分,则该事务在触发器完成之前无法提交。如果事务尚未提交,那么其他会话上的观察者将无法看到其中的任何更改。

      无论如何,将更新后的字段作为参数传递给 UDF 已经很好地解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2011-05-12
      • 1970-01-01
      • 2016-03-22
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 2012-07-23
      • 2011-12-30
      • 1970-01-01
      相关资源
      最近更新 更多