Doctrine 2 migration - transaction in postUp

1.4k views Asked by At

I want to use the postUp() to import some data, after structural database changes are done in the up() method. The import should be done in a transaction using DBAL API. However, the inserts seem to be committed one after another. This can be observed if an error happens in the middle of the import such as 'Duplicate key' error. The inserts that were executed before the error, would be committed to the database even though a rollback was initiated. What seems to break the transactional behaviour are any DDL statements in the up() method.

Consider the following:

public function up(Schema $schema) : void
{
    // this up() migration is auto-generated, please modify it to your needs
    $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');

    $this->addSql('CREATE TABLE user (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET UTF8 COLLATE UTF8_unicode_ci ENGINE = InnoDB');

}

public function postUp(Schema $schema)
{

        /**
         * @var EntityManager $em
         */
        $em = $this->container->get('doctrine.orm.entity_manager');

        $em->getConnection()->transactional(function ($conn) {

             $conn->executeUpdate("INSERT INTO user (id,name) VALUES(1,'Josh')");
             $conn->executeUpdate("INSERT INTO user (id,name) VALUES(1,'Will')");
        });
}

Now, the second insert statement will result in a '1062: Duplicate key' error and will trigger a call to rollback() on the connection instance. However, the actual rollback does not happen and the first inserted row stays in the database. I actually tracked the execution using a debugger and commit() was never called, rollback() was called, as it should, but the end result is as if it's the opposite. I also tried performing the inserts without wrapping them in transactional(), the behaviour is the same.

However, if there are no DDL statements in the up() method (e.g. if the user table already exists), then the transaction works as expected and the user table remains empty, with or without wrapping the insert statements in transactional. What am I doing or understanding wrong here and how to do this properly?

0

There are 0 answers