2012-12-01 148 views
0

我有一個非常怪異的PDO行爲。我不會詳細討論太多的時間,但基本上我觀察到的是,當我重新使用執行簡單INSERT的\ PDOStatement時,在調用PDO :: lastInsertId時,我會得到一個錯誤的值)。準備好的語句和錯誤lastInsertId

我第一次執行該聲明,它工作正常,我找回正確的ID。後續執行將始終返回「0」。這更奇怪,因爲它只發生在測試(PHPUnit)之間。所以說我在test1(working)中使用準備好的語句執行插入,在test2中它會失敗。

當執行多次在非單元測試環境準備的語句(以一個簡單的PHP文件來回實例)這一切工作正常,最後插入的ID始終準確。確實很奇怪。

這裏的測試(注意PersistencyManagerInstance是PersistencyManager的只是一個普通的intsance):

<?php 

class PersistencyManagerTest extends PHPUnit_Framework_TestCase { 

    const DELETE_ALL = "TRUNCATE user"; 
    const ADD_USER = "INSERT INTO user values(null, :username, :password)"; 
    const CHECK_USER_EXISTENCE = "SELECT * FROM user WHERE username = :username AND password = :password"; 
    const DELETE_USER_BY_ID = "DELETE FROM user WHERE id = ?"; 

    protected $manager = null; 

    public function __construct() { 
     $this->manager = new PersistencyManagerInstance(PDOFactory::build()); 
    } 

    public function setUp() { 
     $this->manager->exec(self::DELETE_ALL); 
    } 

    public function tearDown() { 
     $this->manager->exec(self::DELETE_ALL); 
    } 

    public function testInsert() { 
     $user = new User("laurent", "password"); 
     $id = $this->manager->insert(self::ADD_USER, $user->export()); 
     $this->assertEquals("1", $id); 
    } 

    public function testInsertAgain() { 
     $user1 = new User("laurent1", "password1"); 
     $id = $this->manager->insert(self::ADD_USER, $user1->export()); 
     $this->assertEquals("1", $id); 
    } 

    public function testQuery() { 
     $user = new User("laurent", "password"); 
     $this->manager->insert(self::ADD_USER, $user->export()); 
     $results = $this->manager->query(self::CHECK_USER_EXISTENCE, $user->export()); 
     $this->assertEquals(1, count($results)); 
    } 

    public function testExec() { 
     $user = new User("laurent", "password---"); 
     $id = $this->manager->insert(self::ADD_USER, $user->export()); 
     $affected = $this->manager->exec(self::DELETE_USER_BY_ID, array($id)); 
     $this->assertEquals(1, $affected); 
    } 
} 

而testInsertAgain不testInsert工作。

和這裏的類:

<?php 

namespace memory\manager; 

use \PDO; 

abstract class PersistencyManager { 

    /** 
    * @var array An array of \PDOStatement objects 
    */ 
    protected static $ps = array(); 

    /** 
    * @var \PDO 
    */ 
    protected $connection = null; 

    protected function prepareStmt($sql) { 
     // return $this->connection->prepare($sql); 
     $key = md5($sql); 
     if (!isset(self::$ps[$key])) { 
     self::$ps[$key] = $this->connection->prepare($sql); 
     } 
     return self::$ps[$key]; 
    } 

    public function __construct(PDO $connection) { 
     $this->connection = $connection; 
     $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    } 

    public function __destruct() { 
     $this->connection = null; 
    } 

    /** 
    * Good for SELECT operations. By default it fetches using arrays. 
    * @param string $sql 
    * @param array $values 
    * @param integer $fetchStyle 
    * @return array A list of matching elements (The elements' type depends on $fetchStyle) 
    */ 
    public function query($sql, array $values = array(), $fetchStyle = PDO::FETCH_ASSOC) { 
     $prepared = $this->prepareStmt($sql); 
     $prepared->execute($values); 
     $prepared->setFetchMode($fetchStyle); 
     $all = $prepared->fetchAll(); 
     $prepared->closeCursor(); 
     return $all; 
    } 

    /** 
    * Good for INSERT operations. 
    * @param string $sql 
    * @param array $values 
    * @return string Last inserted element's id in string format 
    */ 
    public function insert($sql, array $values = array()) { 
     $prepared = $this->prepareStmt($sql); 
     $prepared->execute($values); 
     $prepared->closeCursor(); 
     return $this->connection->lastInsertId(); 
    } 

    /** 
    * Good for all the remaining routines. 
    * @param string $sql 
    * @param array $values 
    * @return integer The number of effected rows 
    */ 
    public function exec($sql, array $values = array()) { 
     $prepared = $this->prepareStmt($sql); 
     $prepared->execute($values); 
     $count = $prepared->rowCount(); 
     $prepared->closeCursor(); 
     return $count; 
    } 
} 

任何想法?

乾杯

+0

我想,如果你把下面的問題的代碼,使用戶不必從堆棧溢出導航離開來查看你的代碼,這將是最好的。只是一個建議:) –

+0

做;)這樣好? – nourdine

回答

0

傢伙,我開始在每個測試一個新的連接。這是原因。