0

我对 PDO 有一个非常奇怪的行为。我不会详细介绍,因为它会占用太多时间,但基本上我观察到的是,当我重新使用执行简单 INSERT 的 \PDOStatement 时,我在调用 PDO::lastInsertId( )。

我第一次执行该语句时它工作正常,我得到了正确的 id。后续执行将始终返回“0”。这更奇怪,因为它只发生在测试之间(PHPUnit 测试)。所以说我在 test1 (工作)中使用准备好的语句执行插入,在 test2 中它将惨遭失败。

在非单元测试环境中(在简单的 php 文件中)多次执行准备好的语句时,一切正常,最后插入的 id 总是准确的。确实很奇怪。

这是测试(注意 PersistencyManagerInstance 只是 PersistencyManager 的一个简单实例):

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

testInsert 有效,而 testInsertAgain 无效。

这是课程:

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

任何想法?

干杯

4

1 回答 1

0

伙计们,我在每次测试中都开始了新的连接。这就是原因。

于 2012-12-02T15:12:27.113 回答