Нуждаюсь в помощи с вложенными атомарными операциями, включающими транзакции PDO

У меня есть два отличных модуля, которые могут использоваться независимо, но Module2 зависит от Module1.

Module2 начинает операцию, которая должна быть атомарной, и он называет операцию в Module1, который также должен быть атомарным.

Принятие я установил PDO:: ATTR_ERRMODE к PDO:ERRMODE_EXCEPTION, следующее в большой степени genericised и отрезанный код приводит к этому: Фатальная ошибка PHP: Неперехваченное исключение 'PDOException' с сообщением 'Уже существует активная транзакция'

Module1:

<?php
class Module1
{
    ...
    public function atomicOperation($stuff)
    {
        $this->pdo->beginTransaction();
        try {
            $stmt = $this->pdo->prepare(...);
            ...
            $this->pdo->commit();
        }
        catch (Exception $ex) {
            $this->pdo->rollBack();
            throw $ex;
        }
    }
}

Module2:

<?php
class Module2
{
    public $module1;
    ...
    public function atomicOperation($stuff)
    {
        $this->pdo->beginTransaction();
        try {
            $stmt = $this->pdo->prepare(...);
            ...
            $this->module1->atomicOperation($stuff);
            ...
            $this->pdo->commit();
        }
        catch (Exception $ex) {
            $this->pdo->rollBack();
            throw $ex;
        }
    }
}

Я не уверен лучший способ пойти об этом - вложенную операцию определенно назовут независимо и абсолютно должна быть атомарной при вызове самостоятельно. Возложение ответственности на пользователя класса справиться с транзакцией и сохранить атомарность не желательно, поскольку я уверен, что пользователи класса никогда не будут осуществлять его.

5
задан Shabbyrobe 28 April 2010 в 12:45
поделиться

1 ответ

Вам нужно создать свой собственный класс, который расширяет PDO и управляет транзакциями. Примерно так:

<?php
class Db extends PDO{
  private $_inTrans = false;

  public function beginTransaction(){
    if(!$this->_inTrans){
      $this->_inTrans = parent::beginTransaction();
    }
    return $this->_inTrans;
  }

  public function commit(){
    if($this->_inTrans){
      $this->_inTrans = false;
      return parent::commit();
    }
    return true;
  }

  public function rollBack(){
    if($this->_inTrans){
      $this->_inTrans = false;
      return parent::rollBack();
    }
    return true;
  }

  public function transactionStarted(){
    return $this->_inTrans;
  }

}

Вам все равно нужно проверять все переданные запросы на случай, если там будет запущена какая-то транзакция.

Модуль 1:

<?php
class Module1
{
    ...
    public function atomicOperation($stuff)
    {
        $transactionAlreadyStarted = $this->pdo->transactionStarted();
        if(!$transactionAlreadyStarted){
            $this->pdo->beginTransaction();
        }
        try {
            $stmt = $this->pdo->prepare(...);
            ...

            if(!$transactionAlreadyStarted && $this->pdo->transactionStarted()){
                $this->pdo->commit();
            }
        }
        catch (Exception $ex) {
            if($this->pdo->transactionStarted()){
                $this->pdo->rollBack();
            }
            throw $ex;
        }
    }
}

Модуль 2:

<?php
class Module2
{
    public $module1;
    ...
    public function atomicOperation($stuff)
    {
        $transactionAlreadyStarted = $this->pdo->transactionStarted();
        if(!$transactionAlreadyStarted){
            $this->pdo->beginTransaction();
        }
        try {
            $stmt = $this->pdo->prepare(...);
            ...
            $this->module1->atomicOperation($stuff);
            ...
            if(!$transactionAlreadyStarted && $this->pdo->transactionStarted()){
                $this->pdo->commit();
            }
        }
        catch (Exception $ex) {
            if($this->pdo->transactionStarted()){
                $this->pdo->rollBack();
            }
            throw $ex;
        }
    }
}
4
ответ дан 14 December 2019 в 19:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: