MySQL - 锁定表或从触发器开始事务

时间:2014-01-24 07:08:40

标签: mysql stored-procedures triggers database-replication

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

  1. 由应用程序1填充和管理的“主”数据库。
  2. 使用standard mechanism从“主”数据库复制的单独主机上的“从属”数据库。
  3. 应用程序2,它独立于应用程序1运行,对从属数据库的只读访问权限非常有限,对其自己的独立数据库具有读写访问权限。
  4. 基本上需要发生的是,当'slave'数据库中某些事情发生变化时,需要通知Application 2,以便它可以检查'slave'数据库的内容并将一些内容写入自己的数据库中。< / p>

    性能不是问题,在发生这种情况时锁定整个“从属”数据库是可以接受的。 关键是要确保在应用程序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足够智能,可以通过让触发器委托给一个程序来检测我是否试图破坏其“从触发器内部无锁定”规则。

    user-defined-function在将结果返回给调用者之前等待Application 2的操作完成,这可能是相关的(如果MySQL复制过程基本上被触发器执行阻止,那么就不需要手动锁定任何东西了;复制过程是唯一能够对“从属”数据库进行更改的过程。

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

    1. 由于MySQL复制过程所做的更新导致触发器触发,这是否意味着复制过程被阻止,直到触发器返回?

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

    3. 编辑 - 这是一个奖励后续问题:

      当应用程序2执行其操作时,它看到的数据不会反映应该位于“从属”数据库中的最新信息。具体而言,作为触发事务的一部分对jobs表所做的任何更新都不会对应用程序2可见。

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

1 个答案:

答案 0 :(得分:2)

好的,基于我自己的研究:

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

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

  3. 仍然不完全确定奖金&#39;问题,但我猜测它与#2有关。如果触发器执行是触发它的事务的一部分,那么该事务在触发器完成之后才能提交。如果交易没有提交,那么其他会话的观察者将无法看到其中的任何变化。

    在任何情况下,将更新的字段作为参数传递给UDF都能很好地解决这个问题。