当 MySQL 中的事务的 rollback() 失败时会发生什么?

2022-09-04 22:20:59
try
{
    Connection conn = ... MySQL connection ...;
    conn.setAutoCommit(false); // transaction starts
    .... do something ....
}
catch (MySQLException e)
{
    try {
        conn.rollback();
    }
    catch (Exception e)
    {
        // What happens now?
    }
}

对于MySQL服务器(InnoDB引擎),如果事务的回滚()失败会发生什么?(即,当 rollback() 运行时网络会正常关闭,等等)

这是否意味着数据库仍然损坏,或者MySQL服务器有没有办法从“未完成”的回滚中恢复?


答案 1

这是否意味着数据库仍然损坏

请注意,在代码片段中,数据库在任何时候都不会损坏。它同时跟踪数据的原始状态和您在交易中所做的更改。

引发的异常是为了客户端的利益,而不是为了服务器。尝试回滚时网络中断会触发异常,以便客户端可以尝试处理它,并且因为正常进行没有用处。从服务器的角度来看,回滚是丢弃事务内容的显式指令。如果 rollback 命令从未到达数据库,则数据库将简单地推迟提交更改,直到它决定不再需要它,此时将清除更改以清除服务器中的内存或磁盘空间。rollback()

如果您以前没有见过它,您可能正在寻找ACID一词;这描述了如何设计数据库和其他并发系统来缓解这些类型的故障。符合 ACID 的数据库旨在保持一致性,即使提交或回滚中途发生物理故障 - 提交更改的最后一步(在数据库内部)应该是原子的,以便它要么成功,要么被丢弃。


作为一个无关紧要的例子,Mercurial在确保提交永远不会使存储库处于不一致状态方面也有类似的关注点。当用户提交更改时,需要将更新写入多个文件,其中任何一个写入都可能失败。因此,它以仔细的顺序进行这些写入,以确保避免不一致。

  1. 首先,将各个文件差异追加到存储库中与变更集 ID 关联的关联 revlog 文件中。
  2. 然后更新列出这些更改的清单,再次绑定到变更集 ID。
  3. 只有在上述所有操作都成功后,变更集 ID 本身才会记录在变更日志中(这是一次原子写入)。如果此写入成功,则提交已成功。

如果Mercurial在revlog或清单文件中遇到未知的变更集ID,它会忽略它;从而确保更改已完全提交或根本不提交。

自从我仔细研究Mercurial内部以来已经有一段时间了,我完全有可能弄得一些混乱,但要点是正确的。


答案 2

推荐