简体   繁体   English

PHP中的数据库事务回滚处理

[英]database transaction rollback processing in PHP

try
{
  $con->beginTransaction();

  $this->doSave($con);

  $con->commit();
}
catch (Exception $e)
{
  $con->rollBack();

  throw $e;
}

The code above is quite standard an approach to deal with transactions, 上面的代码是处理交易的非常标准的方法,

but my question is:what if $con->rollBack() also fails? 但是我的问题是:如果$con->rollBack()也失败了怎么办?

It may cause db lock,right?If so,what's the perfect way to go? 可能会导致数据库锁定,对吗?如果是这样,什么是理想的选择?

When using transactions, the basic idea is that nothing will actually get permanently written to the database until commit is called. 使用事务时,基本思想是在调用commit之前,不会有任何东西真正永久地写入数据库。

A couple of situations : 几种情况:

  • If you : 如果你 :
    • begin a transaction 开始交易
    • execute some queries 执行一些查询
    • rollback 回滚
    • Then the queries are rolled-back ; 然后查询被回滚; which means their result is not written to the database. 这意味着它们的结果未写入数据库。
  • If you : 如果你 :
    • begin a transaction 开始交易
    • execute some queries 执行一些查询
    • disconnect (which happens if your PHP script ends -- for instance, because of a Fatal Error or a die ) 断开连接(如果你的PHP脚本结束这恰好-例如,因为一个致命错误或的die
    • Then, the queries are not commited -- which means they are not written to the database ; 然后,不提交查询-这意味着它们不会被写入数据库; which means it's the same as if there had been a rollback . 这意味着就像发生了rollback


To makes things simple : starting from the begin transaction , nothing gets permanently written to the database, until you send a commit . 简单地说:从begin transaction ,直到您commit ,所有内容都不会永久写入数据库。 If there is no commit... Nothing is permanently written, and when your PHP script disconnects from the DB, the DB "cancels" what that PHP script did not commit. 如果没有提交,则不会永久写入任何内容,并且当您的PHP脚本与数据库断开连接时,数据库会“取消”该PHP脚本未提交的内容。

Of course, this is exactly the same if you are using something else than PHP to connect to your database -- like the command-line MySQL client, for instance. 当然,如果您使用的是PHP以外的其他东西来连接数据库,则这完全相同-例如,命令行MySQL客户端。

MySQL handles an error situation by rolling back the transaction itself. MySQL通过回滚事务本身来处理错误情况。

Rolling back can be a slow operation that may occur implicitly without the user having explicitly asked for it (for example, when an error occurs). 回滚可能是一个缓慢的操作,可能会隐式发生,而无需用户明确要求(例如,发生错误时)。

The MySQL documentation covers your "what if case" MySQL文档涵盖了您的“假设情况”

If a session that has autocommit disabled ends without explicitly committing the final transaction, MySQL rolls back that transaction. 如果禁用了自动提交的会话在没有显式提交最终事务的情况下结束,则MySQL将回滚该事务。

Further: 进一步:

Both commit and rollback release all InnoDB locks that were set during the current transaction. 提交和回滚都将释放在当前事务期间设置的所有InnoDB锁。

Edit: I set up a test for your proposed situation. 编辑:我为您的建议情况进行了测试。 Using an innoDB table with MySQL 5. 在MySQL 5中使用innoDB表。

$db = new DB();
$db->beginTransaction();
$db->exec("INSERT INTO `table` (`val`) VALUES('commit?')");
sleep(30);
$db->commit();

This works as I've described below in the comments. 正如我在下面的评论中所描述的那样。 If allowed to complete, the transaction is committed to the table after 30 seconds. 如果允许完成,则在30秒后将事务提交到表。

If I kill the script before allowing it to complete, the transactions is rolled back and the table is left in a clean state - as expected. 如果我在允许脚本完成之前将其杀死,则事务将回滚,并且表将保持干净状态-如预期的那样。

Use a transactional database engine, such as InnoDB . 使用事务数据库引擎,例如InnoDB This will guarantee data integrity in the event of a query failure during a write. 如果在写入过程中查询失败,这将保证数据完整性。 MySQL defaults to using the MyISAM engine, which is faster and is not transactional. MySQL默认使用MyISAM引擎,该引擎速度更快且不具有事务性。 All you need to do is change the storage engine when creating your database. 您需要做的就是在创建数据库时更改存储引擎。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM