One feature of Mysql that is often overlooked is transactions. Transactions allow you to preform multiple queries and rollback the changes if any one fails.
In mysql, only InnoDB tables have transaction support. MyISAM, which is often the default table type, does not support this.
Let's say you are transferring funds between 2 accounts. You withdraw the money in one query and deposit the money in another one. What happens if the deposit query fails? The money just disappears. Transactions are an easy way to solve this problem.
We must add some helper functions to our mysql config file. First we'll make a wrapper function for mysql_query(). It takes a query and an optional error message.
function query_db($query,$error="Error") { //perform query $result = mysql_query($query); if(!$result) //query fails { //exit with error message exit($error."<br>$query<br> ".mysql_error()); } else //query succeeds return $result; }
Next, are three transaction functions, begin_transaction(), commit_transaction(), and rollback_transaction().
//Begins the transaction //Every query after this can be rolled back function begin_transaction() { query_db("SET AUTOCOMMIT=0"); query_db("BEGIN"); //Set the $begin_transaction variable to true //so that other functions know a transaction started global $begin_transaction; $begin_transaction = true; } //Commits all queries. Changes cannot be undone after this function commit_transaction() { //if transaction is started, commit changes global $begin_transaction; if($begin_transaction) query_db("COMMIT"); //update global variable $begin_transaction = false; } //Rolls back all queries. All changes are canceled. function rollback_transaction() { //if transaction is started, roll back changes global $begin_transaction; if($begin_transaction) query_db("ROLLBACK"); //update global variable $begin_transaction = false; }
We need to alter the query_db() function to rollback changes if an error occurs.
function query_db($query,$error="Error") { //get global variable global $begin_transaction; //perform query $result = mysql_query($query); if(!$result) //query fails { //if transaction is started, rollback changes if($begin_transaction) rollback_transaction(); //exit with error message exit($error."<br>$query<br> ".mysql_error()); } else //query succeeds return $result; }
That's all you need to use transactions. Here's an example of how to use this.
<?php begin_transaction(); query_db("UPDATE accounts SET balance = balance-500 WHERE id=1" ); query_db("UPDATE accounts SET balance = balance+500 WHERE id=2" ); commit_transaction(); ?>
If either query fails, both accounts are unaffected. If both queries succeed, the accounts are updated.
Sometimes, you want to make sure a row is affected, not just that the query succeeded. I didn't build this into the functions, but it's easy to implement. Here's a simple way to do it:
<?php begin_transaction(); query_db("UPDATE accounts SET balance = balance-500 WHERE id=1" ); if(!mysql_affected_rows()) //no rows affected exit("error".rollback_transaction()); query_db("UPDATE accounts SET balance = balance+500 WHERE id=2" ); if(!mysql_affected_rows()) //no rows affected exit("error".rollback_transaction()); commit_transaction(); ?>
Transactions also help with testing an application. You can perform 20 queries, do some tests, and then roll back the changes automatically. Think of how much time this could save.
0 comments:
Post a Comment