У меня есть два отличных модуля, которые могут использоваться независимо, но 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;
}
}
}
Я не уверен лучший способ пойти об этом - вложенную операцию определенно назовут независимо и абсолютно должна быть атомарной при вызове самостоятельно. Возложение ответственности на пользователя класса справиться с транзакцией и сохранить атомарность не желательно, поскольку я уверен, что пользователи класса никогда не будут осуществлять его.
Вам нужно создать свой собственный класс, который расширяет 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;
}
}
}