2010-04-28 34 views
5

Tôi có hai mô-đun riêng biệt có thể được sử dụng độc lập, nhưng Module2 phụ thuộc vào Module1.Cần trợ giúp với các hoạt động nguyên tử lồng nhau liên quan đến các giao dịch PDO

Module2 có một thao tác cần phải là nguyên tử và nó gọi một phép toán trong Mô-đun 1 cũng cần phải là nguyên tử.

Giả sử tôi đã thiết PDO :: ATTR_ERRMODE để PDO: ERRMODE_EXCEPTION, sau đây nặng nề genericised và snipped đang mang này: PHP Fatal error: của router 'PDOException' với thông điệp 'Đã có một giao dịch tích cực'

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

tôi không chắc chắn cách tốt nhất để đi về vấn đề này - hoạt động lồng nhau chắc chắn sẽ được gọi độc lập và hoàn toàn là phải là nguyên tử khi được gọi theo đúng nghĩa của nó. Việc đặt onus vào người dùng của lớp để quản lý giao dịch và bảo toàn nguyên tử không phải là điều mong muốn vì tôi chắc chắn rằng người dùng của lớp sẽ không bao giờ thực thi nó.

Trả lời

4

Bạn cần tạo lớp của riêng bạn mở rộng PDO và quản lý giao dịch. Một cái gì đó như:

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

} 

Bạn vẫn cần phải kiểm tra tất cả các truy vấn trong trường hợp một số giao dịch được bắt đầu ở đó.

Học phần 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; 
     } 
    } 
} 

Học phần 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; 
     } 
    } 
} 
+0

Đã thêm một số lông tơ. Hoạt động nguyên tử của bạn sẽ có thể sử dụng giao dịch một mình hoặc với bạn bè xung quanh họ. – Arkh

1

giải pháp Arkh, mặc dù gần, là sai vì cam kết() và rollback() là cơ bản nằm. Gọi rollback() hoặc cam kết() có thể trở lại đúng khi không có gì thực sự xảy ra.

Thay vào đó, bạn nên sử dụng SAVEPOINTs.

Savepoints are supported in some form or other in database systems like PostgreSQL, Oracle, Microsoft SQL Server, MySQL, DB2, SQLite (since 3.6.8), Firebird and Informix (since version 11.50xC3). Savepoints are also defined in the SQL standard.

Trong lớp DB tùy chỉnh, bạn ghi đè cam kết, rollback và beginTransaction() và sử dụng SAVEPOINT khi thích hợp. Bạn cũng có thể thử thực hiện inTransaction(), mặc dù hãy cẩn thận rằng các cam kết ngầm định (CREATE TABLE, vv) trong MySQL sẽ làm hỏng độ tin cậy của điều này.

blog post from 2008 thực sự có triển khai thực hiện những gì tôi nói.

This code will only attempt to use the SAVEPOINT code if you’re using a database driver that supports it

Các vấn đề liên quan