在高水平上,我拥有的是:
- 由应用程序1填充和管理的"主"数据库。
- 使用标准机制从"主"数据库复制的单独主机上的一个"从属"数据库。
- 应用程序2,该应用程序独立于应用程序1运行,并且对从属数据库的读取访问非常有限,并且可以读取对其自己的单独数据库的访问。
基本上需要发生的事情是,当某些事物在"从"数据库应用程序中发生变化时,需要通知2,以便它可以检查"从属"数据库的内容并将一些内容写入其自己的数据库。/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 ;
...并且由于您无法从触发器内启动交易或锁定数据库,因此我还具有以下 Procedure :
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 ;
该过程正在调用用户定义的函数,该功能使用libcurl与应用程序2联系,并让它知道它需要处理工作。
当我在MySQL命令行中手动调用它时,该过程正常工作。但是,当它从触发器调用时,MySQL日志中出现以下错误:
Explicit or implicit commit is not allowed in stored function or trigger
...显然MySQL足够聪明,可以检测到我试图通过将触发委托给程序来颠覆其"触发内部无锁定"规则。
用户定义的功能等待应用程序2的操作完成,然后再将结果返回其呼叫者,这可能是相关的(如果触发执行基本上阻止了MySQL复制过程,则无需手动锁定任何内容;复制过程是唯一能够更改"从"数据库的东西)。
无论如何,我想这里有两个问题:
由于MySQL复制过程的更新导致触发器触发,这是否意味着复制过程被阻止直到触发返回?
如果没有,如何锁定数据库或以其他方式停止触发器的复制过程?我想从扳机内部发出
STOP SLAVE;
可能会这样做?
编辑 - 这是一个奖励后续问题:
应用程序2进行操作时,它所看到的数据不会反映"从"数据库中应包含的最新信息。具体而言,作为触发事务的一部分,对jobs
表进行的任何更新均不可见。
鉴于触发器配置为发射AFTER UPDATE
,为什么会这样?是否有任何方法可以使新内容可见到数据库中的应用程序2,或者有必要手动收集和传递所有更新的字段值作为发送的通知的一部分?
好吧,因此,基于我自己的研究:
-
触发器执行是同步的,并阻止调用线程直到触发完成。默认情况下,MySQL复制本质上是一个单线程进程(我认为,即使您启用了多线程复制,每个数据库也只能获得一个线程)。因此,在我的情况下,为所有实际目的而将复制线程"锁定"数据库"锁定";除了具有写入权限的复制线程以外,没有人。
-
您不明确。但是,触发器的执行被认为是触发该触发的交易的一部分,这意味着您可能被隐式锁定/无论如何都可以在原子事务中锁定。发生这种情况的程度似乎取决于您的存储引擎和交易隔离设置。
-
仍然不完全确定"奖金"问题,但我会推测它与#2有关。如果触发器执行是触发该交易的一部分,则该事务直到触发后才能提交。如果交易尚未提交,那么其他会话的观察者将无法看到其中的任何更改。
在任何情况下,将更新的字段作为参数传递给UDF,已经很好地解决了此问题。