Противно на отговора на всички останали, можете ефективно да създавате транзакции в транзакции и това е наистина лесно. Просто създавате местоположения на SAVEPOINT и използвате ВРЪЩАНЕ КЪМ точка на запис за връщане на част от транзакцията, където точка на запис е каквото и име давате на точката за запис. Връзка към документацията на MySQL:http://dev.mysql.com/doc/refman/5.0/en/savepoint.html И разбира се, никоя от заявките никъде в транзакцията не трябва да е от типа, който имплицитно извършва ангажимент, или цялата транзакция ще бъде ангажирана.
Примери:
START TRANSACTION;
# queries that don't implicitly commit
SAVEPOINT savepoint1;
# queries that don't implicitly commit
# now you can either ROLLBACK TO savepoint1, or just ROLLBACK to reverse the entire transaction.
SAVEPOINT savepoint2;
# queries that don't implicitly commit
# now you can ROLLBACK TO savepoint1 OR savepoint2, or ROLLBACK all the way.
# e.g.
ROLLBACK TO savepoint1;
COMMIT; # results in committing only the part of the transaction up to savepoint1
В PHP съм написал код като този и той работи перфектно:
foreach($some_data as $key => $sub_array) {
$result = mysql_query('START TRANSACTION'); // note mysql_query is deprecated in favor of PDO
$rollback_all = false; // set to true to undo whole transaction
for($i=0;$i<sizeof($sub_array);$i++) {
if($sub_array['set_save'] === true) {
$savepoint = 'savepoint' . $i;
$result = mysql_query("SAVEPOINT $savepoint");
}
$sql = 'UPDATE `my_table` SET `x` = `y` WHERE `z` < `n`'; // some query/queries
$result = mysql_query($sql); // run the update query/queries
$more_sql = 'SELECT `x` FROM `my_table`'; // get data for checking
$result = mysql_query($more_sql);
$rollback_to_save = false; // set to true to undo to last savepoint
while($row = mysql_fetch_array($result)) {
// run some checks on the data
// if some check says to go back to savepoint:
$rollback_to_save = true; // or just do the rollback here.
// if some check says to rollback entire transaction:
$rollback_all = true;
}
if($rollback_all === true) {
mysql_query('ROLLBACK'); // rollback entire transaction
break; // break out of for loop, into next foreach
}
if($rollback_to_save = true) {
mysql_query("ROLLBACK TO $savepoint"); // undo just this part of for loop
}
} // end of for loop
mysql_query('COMMIT'); // if you don't do this, the whole transaction will rollback
}