views:

313

answers:

4
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?

It may cause db lock,right?If so,what's the perfect way to go?

A: 

MySQL handles an error situation by rolling back the transaction itself.

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"

If a session that has autocommit disabled ends without explicitly committing the final transaction, MySQL rolls back that transaction.

Further:

Both commit and rollback release all InnoDB locks that were set during the current transaction.

Edit: I set up a test for your proposed situation. Using an innoDB table with MySQL 5.

$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.

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.

jasonbar
But exception in php doesn't necessarily lead to error situation in database layer.Say,the DBMS may not be aware of it .
@user198729: A failed rollback implies that either: 1. Your connection to the db has been dropped or 2. A db error. In either case, the transaction is rolled back by the DBMS.
jasonbar
What if the programme got killed accidently?
@user198729: Then the DBMS will still rollback the transaction. If there is no explicit or implicit `commit`, the DBMS has no choice but to revert to its previous state.
jasonbar
Nothing appears in the table doesn't mean the transaction is rolled back,as I said,it may cause a lock
@user198729: But it wasn't. I should have clarified that. I mean I guess your application could fail, and then the DBMS could fail to clean up, but what do you expect to be able to do in that case?
jasonbar
@user198729: I've updated my answer with documentation from MySQL that covers your error scenario.
jasonbar
It says "if a session ends",the problem is the programme get killed doesn't necessary mean the session will end.Think that we can connect to mysql via a promt but doing nothing for a while,the connection will stay alive for quite a while.
A: 

Use a transactional database engine, such as 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. All you need to do is change the storage engine when creating your database.

Drew
+3  A: 

When using transactions, the basic idea is that nothing will actually get permanently written to the database until commit is called.

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)
    • 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.


To makes things simple : starting from the begin transaction, nothing gets permanently written to the database, until you send a 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.

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.

Pascal MARTIN
In MySQL,begin transaction is `begin;`,and table may be locked until you issue the other `commit` or `rollback`.Nothing is written,but table get locked.
It might, until your script dies ;;; considering PHP scripts don't last long *(to serve webpages, you can't have a script that lasts more than a few seconds)*, and that the probably of a failure on rollback is probably something like 0, I wouldn't worry about that, actually -- and, as a matter of fact, in my every-day job, I don't ;;; what matters is that you are using begin + commit or rollback, depending on the situation -- which is what you are doing.
Pascal MARTIN
I ran a little test on this situation, mysql handles it correctly by fully rolling back the transaction and releasing any locks. See my answer above if you care..
jasonbar
A: 

I think the above comment posted by Drew about MyISAM being faster is very misleeding and has in the past caused me to choose MyISAM over InnoDB over transactional functionality because I thought I was going to be losing alot of speed!

In regards to the original question... I find myself still learning PHP/MySQL and as my app has grown bigger I've needed to wrap things in a transaction... the code posted above is quite useful and it may mean I need to rethink about how everything is coded up to yet! I used to have begin/commit within functions but when these functions call other functions that may need to be in a transaction... it doesn't work that well :s

Intellix