Как можно определить объект PHP PDO, если он уже находится в транзакции MySQL? - PullRequest
6 голосов
/ 01 сентября 2010

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

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

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

Итак, внутри функции delete_A () я выполняю эти операторы внутри транзакции. Внутри функции delete_B () я хочу выполнить одну большую большую транзакцию, которая охватывает действия внутри delete_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();
}

Ответы [ 3 ]

8 голосов
/ 01 сентября 2010

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

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

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

Смотри также:

2 голосов
/ 01 октября 2010

В итоге я использовал исключение, выданное ->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() работает без модификации.

1 голос
/ 01 сентября 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...