Как объект PHP PDO может вычислить, если он уже находится в транзакции MySQL?



У меня есть два сложных PHP-объекта, каждый из которых имеет данные в нескольких таблицах MySQL.



Иногда мне просто нужно удалить один объект A из базы данных, и для этого требуется 3 инструкции SQL.



Иногда мне нужно удалить один объект B Из базы данных, который принимает 4 оператора SQL, и который также должен найти и удалить все объекты A, которыми владеет объект B.



Таким образом, внутри функции delete_A () я выполняю эти инструкции внутри транзакции. Внутри функции delete_B () я хочу запустить одну большую транзакцию, которая охватывает действия внутри delete_A (). Если весь атом удаления A B терпит неудачу, мне нужно восстановить все его A в откате.



Как обновить определение delete_A (), чтобы открыть только новую транзакцию , Если уже не выполняется более крупная транзакция.



Я ожидал, что смогу сделать что-то подобное, но атрибут autocommit, похоже, не изменяется beginTransaction()



function delete_A($a){
global $pdo;
$already_in_transaction = !$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
if(!$already_in_transaction){
$pdo->beginTransaction();
}

//Delete the A

if(!$already_in_transaction){
$pdo->commit();
}
}
function delete_B($b){
global $pdo;
$pdo->beginTransaction();
foreach($list_of_As as $a){
delete_A($a);
}
$pdo->commit();
}
734   3  

3 ответов:

PDO::ATTR_AUTOCOMMIT это не атрибут индикатора, это атрибут управления. Он определяет, будут ли операторы SQL неявно фиксироваться, когда они завершатся.

Вы можете вызвать PDO::inTransaction(), который возвращает 0, Если у вас нет незавершенной транзакции, и 1, Если у вас есть незавершенная транзакция, которую необходимо зафиксировать или откатить. Однако эта функция не задокументирована, поэтому трудно сказать, безопасно ли полагаться на то, что она присутствует во всех будущих версиях PDO.

Я рекомендую использовать PHP разработчики не пытаются управлять транзакциями в рамках функций или классов. Вы должны управлять транзакциями на верхнем уровне приложения.

См. также:

В итоге я просто использовал исключение, вызванное ->beginTransaction(), чтобы выяснить, был ли я в транзакции, и с его помощью решить, следует ли фиксировать во внутреннем цикле. Так что delete_A() в итоге выглядело так:

function delete_A($a){
  global $pdo;
  try {
    $pdo->beginTransaction();
  } catch (PDOException $e) {
    $already_in_transaction = true;
  }

  //Delete the A

  if(!$already_in_transaction){
    $pdo->commit();
  }
}

И delete_B() работает без изменений.

Один из способов-создать свой собственный класс PDOConnect, который имеет переменную $hasTransaction. Тогда ты просто проверь это. Пример можно найти в комментариях функции beginTransaction на php.net здесь http://www.php.net/manual/en/pdo.begintransaction.php#81022

Это было бы моим предпочтением. Конечно, этот пример потребует настройки и переодевания и т. д., Но он должен быть хорошим фундаментом для начала.

Боковое Примечание помните, что ваш стол должен быть INNODB для сделки, чтобы работать. И так как вы должны быть в INNODB для транзакций, чтобы работать, вы должны принять Совет prodigitalson и использовать ограничения внешнего ключа.

Comments

    Ничего не найдено.