ZF-8500: Mysql does not support nested transactions, code ignitor specifically supports this, zend does not (yet)

Issue Type: Improvement Created: 2009-12-08T15:19:32.000+0000 Last Updated: 2012-11-20T21:37:53.000+0000 Status: Open Fix version(s): Reporter: Josh Ribakoff ( Assignee: None Tags: - Zend_Db_Adapter_Mysqli

Related issues: Attachments: - transaction_emulation.patch


I noticed if you nest transactions, if the inner transaction commits but the outer transaction rolls back, the changes take effect and ZF does not throw any exceptions or handle that nicely. It appears from this thread ( that CI has a feature that makes it so only the outer commit/rollback takes effect.

This prevented me from testing code that uses Zend_Db & transactions, because my test itself needed to rollback any changes that happened during the test. But the code I was testing had it's own beginTransaction() and commit()

I guess in code ignitor that inner commit() would be ignored.


Posted by Josh Ribakoff ( on 2009-12-08T15:48:31.000+0000

Possible patch is attached. The $_should_emulate_nesting flag which defaults to false will retain it's current behavior. Setting the flag to true mimics code ignitor's feature (which makes my green bar happy)

Posted by Josh Ribakoff ( on 2009-12-08T16:46:49.000+0000

Fixed isNested() method (see patch2)

Posted by Josh Ribakoff ( on 2009-12-08T17:27:19.000+0000

After trying it out in some more unit tests, it appears patch 3 would hold the correct logic.

It should be noted 1 caveat of using this patch, and enabling the flag, would be that extraneous calls to commit would put the transaction counter of sync. But this is good enough for my own development (I wrapped the adapter seeing as you may not desire to use this functionality in the zend core)

Posted by Josh Ribakoff (jshpro2) on 2010-09-24T23:19:22.000+0000

On PDO you get an exception when you call beginTransaction() more than once, so I augmented the code like this:

function beginTransaction() { $this->_transaction_depth++; if( $this->_transaction_depth > 0 ) { return; } return parent::beginTransaction(); }

Posted by Josh Ribakoff (jshpro2) on 2010-09-24T23:23:10.000+0000

I should also note, this specific behavior (how it works now) is detrimental to unit testing. If you have a piece of code that uses the database, the standard unit testing practice is to wrap the unit test method in a transaction itself. However if the SUT tries to start it's own transaction, or commit it's "inner" transaction - you either crash your tests - or worse yet the "inner" transaction would be committed, leaving global state for the next unit test method.

As you can see, the way it works now is completely contrary to best practices. (in regards to this one issue - the rest of the component is terrific)

Posted by Josh Ribakoff ( on 2010-11-10T11:45:38.000+0000

One pitfall to this I discovered over the months, you'd have to make the 'nest' count a public property, and the user should remember to reset it to -1 when catching exceptions.

Have you found an issue?

See the Overview section for more details.


© 2006-2018 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.