我有两个可以独立使用的不同模块,但是 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/