Mat*_*mes 7 mysql mariadb transaction
我有一个带有 InnoDB 表的 MariaDB 数据库。我有两个连接到同一个数据库。一个连接是围绕大量工作使用事务。另一个连接的任务是更新同一数据库中的表(但在事务工作范围之外)以跟踪事务的进度。
所有这一切都发生在同一个脚本中,但同样具有不同的连接:一个用于正在执行的实际工作(包括交易),另一个用于保留有关工作进度的元信息。
我预计这会起作用,以便作业跟踪记录会随着作业的进展而更新 - 10%、20%、50% 等,因为事务工作是在单独的连接上完成并影响其他表。但是,在我的测试中,在提交作业的事务之前,作业跟踪记录不会更新。
据我所知,它不会死锁,因为“进度监控”连接根本没有使用事务。“worker”连接将其查询包装在一个事务中,但另一个连接没有。
我通过查看随着工作的进展而填写的“完成百分比”字段来检查进度。操作顺序是:
然后,在另一个 HTTP 连接中,我正在轮询并输出进度值,但在连接 1 上的事务提交之前它永远不会更新。
除了将作业跟踪表移动到完全不同的数据库之外,有什么方法可以获得我想要的行为?
您看到的是默认隔离设置 ( REPEATABLE READ) 甚至较低 ( READ COMMITTED) 设置的正确行为。更多细节可以在 MariaDB 和 MySQL 文档中找到:
基本上总结为:
一个事务正在写入什么,其他事务应该无法读取。不是在一个事务提交之前。
当事务向数据库写入内容时,无法保证写入会持续。事务可能会出错,并且它所做的所有写入都将回滚。所以,你观察到的
但是,在我的测试中,在提交作业的事务之前,作业跟踪记录不会更新。
从这个角度来看是正确的。从外面看不到任何东西,进度为 0,直到提交某些内容。这就是事务的隔离属性的全部意义所在。
我看到该问题的 2 个解决方案:
A. 也使用“worker”,事务 1 进行进度报告。有谁比工人本身更了解它的工作进展了多少?
B. 在第 2 个“进度报告”连接中,使用最低隔离设置 ( READ UNCOMMITTED):
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
Run Code Online (Sandbox Code Playgroud)
现在,来自此连接的事务将能够执行“脏读”,即查看第一个事务中未提交的写入,并将正确报告(未提交的)进度。
其他建议的解决方案似乎都不适合我。相反,我最终将“作业进度”表从 InnoDB 切换到 MyISAM。由于MyISAM不支持事务,因此即使在事务期间记录也会立即写入表中。
将来,我希望有一种替代方法来将所有表保留在 InnoDB 中以保持一致性,但这是我发现唯一适合我的解决方案。