Php 需要有关涉及PDO事务的嵌套原子操作的帮助吗

Php 需要有关涉及PDO事务的嵌套原子操作的帮助吗,php,pdo,Php,Pdo,我有两个可以独立使用的不同模块,但是Module2依赖于Module1 Module2有一个需要原子化的操作,它在Module1中调用一个也需要原子化的操作 假设我已将PDO::ATTR_ERRMODE设置为PDO:ERRMODE_EXCEPTION,则以下经过大量泛化和剪切的代码将产生以下结果: PHP致命错误:未捕获异常“PDOException”,消息为“已存在活动事务” 模块1: <?php class Module1 { ... public function a

我有两个可以独立使用的不同模块,但是Module2依赖于Module1

Module2有一个需要原子化的操作,它在Module1中调用一个也需要原子化的操作

假设我已将PDO::ATTR_ERRMODE设置为PDO:ERRMODE_EXCEPTION,则以下经过大量泛化和剪切的代码将产生以下结果: PHP致命错误:未捕获异常“PDOException”,消息为“已存在活动事务”

模块1:

<?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;
        }
    }
}

您需要创建自己的类来扩展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;
  }

}

Arkh的解决方案虽然正确,但不可靠,因为
commit()
rollback()
基本上都是谎言。调用
rollback()
commit()
可能会在实际没有发生任何事情时返回true

相反,您应该使用

保存点在数据库系统中以某种形式受到支持,如PostgreSQL、Oracle、Microsoft SQL Server、MySQL、DB2、SQLite(自3.6.8版起)、Firebird和Informix(自11.50xC3版起)。保存点也在SQL标准中定义

在自定义DB类中,可以重写commit、rollback和beginTransaction(),并在适当的地方使用保存点。您也可以尝试实现inTransaction(),不过请注意MySQL中的隐式提交(创建表等)会破坏其可靠性

这实际上实现了我所说的

只有在使用支持保存点代码的数据库驱动程序时,此代码才会尝试使用该代码


添加了一些绒毛。您的原子操作将能够单独使用事务或与他们周围的朋友一起使用事务。
<?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;
  }

}
<?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;
        }
    }
}
<?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;
        }
    }
}