php - 在涉及 PDO 事务的嵌套原子操作方面需要帮助

标签 php pdo

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

模块 2 有一个操作需要是原子的,它调用模块 1 中的一个操作也需要是原子的。

假设我已将 PDO::ATTR_ERRMODE 设置为 PDO:ERRMODE_EXCEPTION,以下高度通用化和截断的代码会产生以下结果: PHP fatal error :未捕获的异常“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;
        }
    }
}

模块 2:

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

我不确定解决此问题的最佳方法 - 嵌套操作肯定会被独立调用,并且在单独调用时绝对必须是原子的。让类的用户负责管理事务和保持原子性是不可取的,因为我确信类的用户永远不会强制执行它。

最佳答案

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

关于php - 在涉及 PDO 事务的嵌套原子操作方面需要帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2729467/

相关文章:

php - 我的PHP中找不到的小错误。意外的T_VARIABLE

php - 如何在 codeigniter 中动态显示选项卡

php - 运行长 PDO 插入语句的更快方法?

php - MySql PDO 开始事务并将其传递给对象

PHP 计数行返回错误

php - 我可以订购 Joomla 错误信息吗?

php - 带有Laravel的Docker因php扩展而失败

php - 如何自动创建 key (如 FBAppid)进行注册?

php - c9.io php pdo 连接到 mysql

php - PDO PostgreSQL 绑定(bind)错误