2010-09-01 2 views
6

У меня есть два сложных объекта PHP, каждый из которых имеет данные в нескольких таблицах MySQL.Как можно определить объект PDO 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(); 
} 
+0

Возможно, вам стоит рассмотреть возможность использования ограничений внешнего ключа (это означает, что вам придется переключиться с myISAM на движок, который их поддерживает) - таким образом вы можете использовать db для каскадирования для вас вместо имитации. – prodigitalson

ответ

2

Я в конечном итоге только с помощью исключения брошенный ->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() работ без изменений.

+0

Что делать, если это вызвано другой процедурой, которая начала транзакцию и решает откат? Ваше удаление будет отменено. –

1

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

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

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

7

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

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

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

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

+0

Спасибо за ссылки, которые привели меня к решению, которое я использовал. –

+2

inTransaction() теперь задокументировано. http://php.net/manual/en/pdo.intransaction.php – morbidCode

+0

@morbidCode, спасибо за обновление! –