tags:

views:

121

answers:

1

I think the question itself is pretty self-explanatory. The code is given below -

<?php
    $PDO = NULL;
    $pdo_dsn = 'mysql:host=localhost;dbname=pdo_test';
    $pdo_persistence = array( PDO::ATTR_PERSISTENT => true );
    $db_user = 'root';
    $db_pass = '';
    $db_query = "INSERT INTO person(name, address)
                    VALUES ('Mamsi Mamsi', 'Katabon')";

    try
    {
            $PDO = new PDO($pdo_dsn, $db_user, $db_pass, 
                              $pdo_persistence);
    }
    catch(PDOException $e)
    {
            echo "Error occured: ". $e->getMessage();
            die();
    }

    $PDO->setAttribute(PDO::ATTR_ERRMODE, 
                           PDO::ERRMODE_EXCEPTION);
    $PDO->setAttribute(PDO::ATTR_AUTOCOMMIT, false);

    try
    {
            $PDO->beginTransaction();
            $PDO->exec($db_query);

            throw new PDOException('Generated Exception');

            $PDO->commit();
    }
    catch(PDOException $e)
    {
            echo "An error occured while doing a database transaction. The 
            error message is : ".$e->getMessage();

            $PDO->rollBack();
            die();
    }
?>

Even if I am rolling back the transaction inside the catch block, data are still being inserted into the database. Why?

EDIT I am adding the following few lines from the documentation for further clarification -

Unfortunately, not every database supports transactions, so PDO needs to run in what is
known as "auto-commit" mode when you first open the connection. Auto-commit mode means 
that every query that you run has its own implicit transaction, if the database 
supports it, or no transaction if the database doesn't support transactions. If you 
need a transaction, you must use the PDO::beginTransaction() method to initiate one. If 
the underlying driver does not support transactions, a PDOException will be thrown 
(regardless of your error handling settings: this is always a serious error condition). 
Once you are in a transaction, you may use PDO::commit() or PDO::rollBack() to finish 
it, depending on the success of the code you run during the transaction. 

Also, the following lines from this page -

bool PDO::beginTransaction  ( void  )

    Turns off autocommit mode. While autocommit mode is turned off, changes made to the 
    database via the PDO object instance are not committed until you end the 
    transaction by calling PDO::commit(). Calling PDO::rollBack() will roll back all 
    changes to the database and return the connection to autocommit mode.

    Some databases, including MySQL, automatically issue an implicit COMMIT when a 
    database definition language (DDL) statement such as DROP TABLE or CREATE TABLE is 
    issued within a transaction. The implicit COMMIT will prevent you from rolling back 
    any other changes within the transaction boundary. 
+9  A: 

You should check that you are using INNODB as your database type. MyISAM does not support transactions.

Brad F Jacobs
The "problem" is that PDO is supposed to raise an exception if you start a transaction using a driver that doesn't support them. Bug? Bad docs?
banzaimonkey
No clue. All I know is that this was an issue for me when I was trying to do transactions using PDO with the MySQL Driver, no exceptions were ever thrown. Could be a bug, I would have to read the docs to make sure though. EDIT: It appears it is not a bug: Returns TRUE on success or FALSE on failure. From the man pages for PDO->beginTransaction
Brad F Jacobs
Docs I referenced are here: http://us2.php.net/manual/en/pdo.transactions.php
banzaimonkey
Oh wow...yea. I would call that a bug, or at least an incorrectly documented issue. That or my code was flawed when I was testing and it was throwing exceptions I just was not handling them right.
Brad F Jacobs
It's very likely that PDO *doesn't know* what the underlying table type is, and whether or not it's transactional or not. (In other words, this might be a feature request, not a bug. Further, it might not even be possible. It would have to actually parse the SQL and ask the server about every table before letting the query go through...)
Charles
@Charles, correct. The documentation is right as it states that it will only throw an exception if the underlying driver does not support transactions. MySQL supports them, the tables just have to be a certain type. So yea, thanks for bringing that to light.
Brad F Jacobs
Daniel Egeberg
@premiso: Yup, you are absolutely right. My database table uses MyISAM, so there is no transaction going on here, which also clarified another thing for me: PDO cannot emulate transactions for databases that don't support it. Thanks!
Night Shade