В PHP-скрипте, работающем с базой данных mysql, мне недавно пришлось использовать транзакцию в точке, которая оказалась внутри другой транзакции. Все мои тесты, похоже, указывают, что это хорошо работает, но я не могу найти никакой документации по этому использованию.
Я хочу быть уверенным – это транзакции в транзакции, действующие в mysql? Если да, есть ли способ узнать, сколько уровней вы находитесь во вложенных транзакциях? (т. е. сколько откатов потребуется, чтобы вернуться к норме)
Спасибо заранее, Брайан
Эта страница руководства может вас заинтересовать: 12.3.3. Заявления, которые вызывают неявное обязательство ; цитируя несколько предложений:
Утверждения, перечисленные в этом разделе (и любые синонимы для них), неявно завершают транзакцию, как если бы вы выполнили
COMMIT
перед выполнением инструкции.
И, немного дальше на странице:
Операции управления транзакциями и блокировки.
BEGIN
,LOCK TABLES
,SET autocommit = 1
(если значение уже не 1),START TRANSACTION
,UNLOCK TABLES
.
См. Также этот параграф:
Транзакции не могут быть вложенными.
Это является следствием неявнойcommit
выполненной для любой текущей транзакции при выдаче инструкцииSTART TRANSACTION
или одного из ее синонимов.
Надеюсь это поможет !
Вопреки всем остальным, вы можете эффективно создавать транзакции в транзакциях, и это очень просто. Вы просто создаете местоположения SAVEPOINT и используете ROLLBACK TO 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. # eg 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 }
Я хочу быть уверенным – это транзакции в транзакции, действующие в mysql?
Нет.
MySql не поддерживает вложенные транзакции. Есть несколько способов, которыми вы можете его эмулировать. Во-первых, вы можете использовать точки сохранения как форму транзакции, так что вы получаете два уровня транзакций; Я использовал это для тестирования, но я не уверен в ограничениях, если вы используете его в производственном коде. Более простым решением является игнорировать вторую begin transaction
и вместо этого увеличивать счетчик. Для каждого commit
вы уменьшаете его. Как только вы нажмете нуль, вы сделаете фактическую commit
. Есть очевидные ограничения этого; Например. откат откатит все транзакции, но для случая, когда вы используете транзакции только для обработки ошибок, это может быть приемлемым.
Однако в этом потоке есть отличные ответы, если вы используете innoDB в качестве механизма хранения MySQL и используете MySQL 5.0.3 или новее, вы получаете вложенные транзакции прямо из коробки без необходимости какой-либо дополнительной работы с вашей стороны или любой из причудливых методов, описанных другими в этой теме.
Из документов MySQL по транзакциям XA:
MySQL 5.0.3 и выше поддерживают серверную поддержку транзакций XA. В настоящее время эта поддержка доступна для механизма хранения InnoDB. Реализация MySQL XA основана на документе X / Open CAE. Обработка распределенных транзакций: спецификация XA. Этот документ публикуется Группой Open и доступен по адресу http://www.opengroup.org/public/pubs/catalog/c193.htm . Ограничения текущей реализации XA описаны в разделе E.5 «Ограничения на транзакции XA».
Мой пример транзакции XA Just For You:
# Start a new XA transaction XA START; # update my bank account balance, they will never know! UPDATE `bank_accounts` SET `balance` = 100000 WHERE `id` = 'mine'; # $100,000.00 is a bit low, I'm going to consider adding more, but I'm not sure so # I will start a NESTED transaction and debate it... XA START; # max int money! woo hoo! UPDATE `bank_accounts` SET `balance` = 2147483647 WHERE `id` = 'mine'; # maybe thats too conspicuous, better roll back XA ROLLBACK; # The $100,000 UPDATE still applies here, but the max int money does not, going for it! XA COMMIT; # Oh No! Sirens! It's the popo's!!! run!! # What the hell are they using ints for money columns anyway! Ahhhh!
Документация MySQL для транзакций XA:
I <3 XA Сделки 4 Ева!
Вы можете проверить свою тестовую метадологию. Вне MaxDB MySQL не поддерживает ничего удаленного, как вложенные транзакции.
Он выполняет следующие действия: http://dev.mysql.com/doc/refman/5.0/en/xa.html