M. of CA
M. of CA

Reputation: 1546

PDO Transaction doesn catch exceptions

I am trying PDO transactions for the first time. The below code doesnt work. the email address we are trying to insert has a duplicate so it should fail. It does give me an error. but the first insert get inserted into the DB and it doesnt roll back. I know rollback work cuase if i move PDO::rollBack into the Try{ before commit, it does roll back. I think the problem is its not catching the error, therefore not calling PDO::rollBack. Any ideas?

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

Upvotes: 0

Views: 2818

Answers (2)

Phil
Phil

Reputation: 165065

PDO::beginTransaction() is not a static method. From your question, it looks like you're extending the PDO class. I wouldn't do that as I doubt you're adding anything significant to the base class. Instead, you should the set the PDO connection as a class property.

For example

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

Upvotes: 4

cwallenpoole
cwallenpoole

Reputation: 82078

I'm just going to start by quoting the docs:

Beware: Some MySQL table types (storage engines) do not support transactions. When writing transactional database code using a table type that does not support transactions, MySQL will pretend that a transaction was initiated successfully. In addition, any DDL queries issued will implicitly commit any pending transactions.

Your problem may be expected behavior. Additionally:

  1. beginTransaction is not static. (I repeat Phil's statement that you should not be extending PDO).
  2. Call $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  3. You never call closeCursor on your statement (this will often cause problems). (Phil points out that it is not explicitly necessary in this case. It is still best practice though).
  4. Using bindParam does not yield any benefit for the userID variable as you are using it (a locally defined variable which is not re-used).

Upvotes: 1

Related Questions