diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-15 15:14:24 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-15 15:14:24 -0500 |
commit | 46728df2b48d2a31b44fecf84c912a3b4d7fee8a (patch) | |
tree | f39456253930de2114af83cd796886dfa17f8309 | |
parent | 789ab9174354bd0a6f2cc0de97a724cadd9a6945 (diff) | |
download | sqlalchemy-46728df2b48d2a31b44fecf84c912a3b4d7fee8a.tar.gz |
- should close the session before rolling back the transaction
- make section title actually say, "such as for test suites"
- add topic section detailing an evented approach to allowing ROLLBACK by using savepoint
-rw-r--r-- | doc/build/orm/session.rst | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/doc/build/orm/session.rst b/doc/build/orm/session.rst index c4d9b0874..ea811aab4 100644 --- a/doc/build/orm/session.rst +++ b/doc/build/orm/session.rst @@ -1648,8 +1648,8 @@ proper context for the desired engine:: .. _session_external_transaction: -Joining a Session into an External Transaction -=============================================== +Joining a Session into an External Transaction (such as for test suites) +======================================================================== If a :class:`.Connection` is being used which is already in a transactional state (i.e. has a :class:`.Transaction` established), a :class:`.Session` can @@ -1686,11 +1686,12 @@ entire database interaction is rolled back:: self.session.commit() def tearDown(self): + self.session.close() + # rollback - everything that happened with the # Session above (including calls to commit()) # is rolled back. self.trans.rollback() - self.session.close() # return connection to the Engine self.connection.close() @@ -1702,6 +1703,46 @@ nested begin/commit-or-rollback pairs where only the outermost begin/commit pair actually commits the transaction, or if the outermost block rolls back, everything is rolled back. +.. topic:: Supporting Tests with Rollbacks + + The above recipe works well for any kind of database enabled test, except + for a test that needs to actually invoke :meth:`.Session.rollback` within + the scope of the test itself. The above recipe can be expanded, such + that the :class:`.Session` always runs all operations within the scope + of a SAVEPOINT, which is established at the start of each transaction, + so that tests can also rollback the "transaction" as well while still + remaining in the scope of a larger "transaction" that's never committed, + using two extra events:: + + from sqlalchemy import event + + class SomeTest(TestCase): + def setUp(self): + # connect to the database + self.connection = engine.connect() + + # begin a non-ORM transaction + self.trans = connection.begin() + + # bind an individual Session to the connection + self.session = Session(bind=self.connection) + + # two events make sure a SAVEPOINT is always started + # for this session. After the initial "begin"... + @event.listens_for(self.session, "after_begin") + def start_savepoint(session, transaction, connection): + if not transaction.nested: + session.begin_nested() + + # ... and after the end of each "transaction", assuming + # the transaction ending was the "nested" transaction + @event.listens_for(self.session, "after_transaction_end") + def restart_savepoint(session, transaction): + if transaction.nested and not transaction._parent.nested: + session.begin_nested() + + # ... the tearDown() method stays the same + .. _unitofwork_contextual: Contextual/Thread-local Sessions |