PDO işlemleri içeren iç içe atomik işlemler ile yardıma ihtiyacı

2 Cevap php

Ben bağımsız kullanılabilen iki farklı modülleri var, ama Module2 Module1'deki bağlıdır.

Module2 atom olması gereken bir operasyon var, ve o da atom olması gereken Module1'deki bir operasyon çağırır.

Assuming I have set PDO::ATTR_ERRMODE to PDO:ERRMODE_EXCEPTION, the following heavily genericised and snipped code yields this: PHP Fatal error: Uncaught exception 'PDOException' with message 'There is already an active transaction'

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

Ben bu konuda gitmek için en iyi yolu, emin değilim - kendi başına çağrıldığında iç içe operasyon kesinlikle must atomik olacak bağımsız ve kesinlikle çağrılır. Ben sınıfın kullanıcıları onu zorlamak asla eminim olarak işlem yönetmek ve bölünmezlik korumak için sınıf 'kullanıcı bir sorumluluk yerleştirme arzu değildir.

2 Cevap

You need to create your own class which extends PDO and manage transaction. Something like :

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

}

Hala bazı işlem başlanması durumunda geçirilen tüm sorguları kontrol etmeniz gerekir.

Modül 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;
        }
    }
}

Modül 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;
        }
    }
}

Arkh çözümü, yakın, wrong commit () ve rollback () çünkü temelde rağmen lying. Hiçbir şey gerçekten oluyor zaman () true döndürebilir geri alma arama () veya taahhüt.

Bunun yerine, kullanmanız gereken SAVEPOINTs.

Savepoints PostgreSQL, Oracle, Microsoft SQL Server, MySQL, DB2, SQLite gibi veritabanı sistemleri bazı form veya diğer desteklenen (3.6.8 beri), Firebird ve Informix (sürüm 11.50xC3 beri). Savepoints da SQL standardında tanımlanmıştır.

Özel DB sınıfında, sen taahhüt geçersiz geri alma ve beginTransaction () ve nerede uygun Savepoints kullanın. MySQL olur pisliği bu güvenilirlik bu örtük kaydedilmesini (TABLO OLUŞTURMA, vb) her ne kadar dikkat de,) (inTransaction uygulamak için deneyebilirsiniz.

Bu blog post from 2008 Aslında ben söylediklerine bir uygulaması vardır.

Bunu destekleyen bir veritabanı sürücüsünü kullanıyorsanız bu kodu yalnızca kayıt noktasına kodunu kullanmaya çalışacaktır