PDO事务没有捕获异常

时间:2011-08-16 00:26:49

标签: php mysql pdo

我是第一次尝试PDO交易。以下代码不起作用。我们尝试插入的电子邮件地址有重复,因此它应该失败。它确实给了我一个错误。但是第一个插入插入到DB中并且它不会回滚。我知道回滚工作如果我将PDO :: rollBack移动到Try {before commit之前,它会回滚。我认为问题是它没有捕获错误,因此没有调用PDO :: rollBack。有什么想法吗?

try {
    PDO::beginTransaction();

$sql = "INSERT INTO .`tblUsersIDvsAgencyID` (`id`, `agency_id`) VALUES (NULL, :agencyID)";
$STH = $this->prepare($sql); 
$STH->bindParam(':agencyID', $AgencyUser['agency_id']);
$STH->execute();
$userID = parent::lastInsertId();

$sql = "INSERT INTO `tblUsersEmailAddress` (`id`, `user_id`, `email_address`, `primary`, `created_ts`, `email_verified`) VALUES (NULL ,  :userID ,  :EmailAddress ,  '1', CURRENT_TIMESTAMP ,  '0' )";
$STH = $this->prepare($sql); 
$STH->bindParam(':userID', $userID);
$STH->bindParam(':EmailAddress', $email_address);
$STH->execute();
PDO::commit();
echo 'Data entered successfully<br />';
}
catch(PDOException $e)
{
/*** roll back the transaction if we fail ***/
PDO::rollBack();
echo "failed";
} 

2 个答案:

答案 0 :(得分:4)

PDO::beginTransaction()不是静态方法。从您的问题来看,您似乎正在扩展PDO类。我不这样做,因为我怀疑你是否在基类中添加了任何重要内容。相反,您应该将PDO连接设置为类属性。

例如

class ParentClass
{
    /**
     * @var PDO
     */
    protected $dbh;

    public function __construct(PDO $dbh)
    {
        $this->dbh = $dbh;

        // Make sure PDO is set to throw exceptions
        $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
}

class ChildClass extends ParentClass
{
    public function insertStuff()
    {
        $this->dbh->beginTransaction();
        try {
            // do stuff

            $this->dbh->commit();
        } catch (PDOException $e) {
            $this->dbh->rollBack();
            throw $e;
        }
    }
}

答案 1 :(得分:1)

我将首先引用文档:

  

注意:某些MySQL表类型(存储引擎)不支持事务。使用不支持事务的表类型编写事务数据库代码时,MySQL将假装成功启动了事务。此外,发出的任何DDL查询都将隐式提交任何挂起的事务。

您的问题可能是预期的行为。此外:

  1. beginTransaction不是静态的。 (我重复菲尔的声明,你不应该扩展PDO)。
  2. 调用$ pdo-&gt; setAttribute(PDO :: ATTR_ERRMODE,PDO :: ERRMODE_EXCEPTION);
  3. 您永远不会在您的陈述上致电closeCursor(这通常会导致问题)。 (菲尔指出在这种情况下没有明确的必要。尽管如此,这仍然是最好的做法。)
  4. 使用bindParam并不会因为使用它而对userID变量产生任何好处(本地定义的变量不会被重复使用)。