假设我有一个修改数据库的函数。这可以是事务中的一个查询到多个查询的任何地方。在这些修改中,我们都希望确保所有查询都是成功的。谢天谢地,对于事务,如果其中一个失败了,我有一种方法可以确保这些更改都不是永久性的。
现在,假设我还有一个日志,需要写入该日志以记录更改。如何确保既进行了修改又写入了日志?
我总是可以对任何一个执行try/catch,例如,我的查询是成功的,但是我的日志不成功。然后,我如何返回并撤消对数据库的所有修改?
这样的事情是有效的和/或可取的吗?
try {
$db->connect();
$db->mysqli->begin_transaction();
// series of queries
...
// log to file
$db->mysqli->commit();
} catch (exception $e) {
$db->mysqli->rollback();
$db->mysqli->close();
}我想记录下我在测试时观察到的一些行为。如果将commit()放在日志之前,即使在日志记录时捕获到异常,数据库更改也不会回滚。
发布于 2020-07-28 06:16:25
一旦调用commit()或触发隐式提交,数据就会存储在数据库中。例如,这不会对数据库进行任何更改,因为没有提交:
$mysqli->begin_transaction();
$mysqli->query('INSERT INTO test1(val) VALUES(2)');
// end of script's execution在您的小示例中,只要您的日志记录功能停止执行或抛出异常,事务就会回滚。
$db->connect();
try {
$db->mysqli->begin_transaction();
// series of queries
...
// log to file
throw new \Exception(); // <-- This will prevent commit from executing.
$db->mysqli->commit();
} catch (\Exception $e) {
// An exception? That's ok, we'll try something different instead.
$db->mysqli->rollback();
}只有当您想要从异常中恢复并清除未保存的缓冲区时,才需要调用rollback。只有当你想从异常中恢复并做一件不同的事情时,你才应该捕捉到异常。否则,可以通过完全删除try-catch和rollback来简化您的代码。
但是,捕获事务中的异常并尽快显式回滚它是一个好主意,即使您不想恢复。如果您在代码中的其他位置捕捉到异常,并尝试执行其他DB操作,则可以防止出现问题。未保存的数据仍然在缓冲区中,直到您关闭会话或回滚!这就是为什么你会经常看到这样的代码:
$db->connect();
try {
$db->mysqli->begin_transaction();
throw new \Exception(); // <-- Something throws an exception
$db->mysqli->commit();
} catch (\Exception $e) {
// rollback unsaved data, but rethrow the exception as we do not know how to recover from it here
$db->mysqli->rollback();
throw $e;
}https://stackoverflow.com/questions/63123361
复制相似问题