Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transaction manager revert/rollback last commit

I try to speedup my tests by putting test data from test case setUp() to setUpClass()/teardownClass class method, so it does not recreate same select only fixture for every test in test case.

@classmethod
def setUpClass(cls):
    plant.StuffFactory() #plant stuff with FactoryBoy
    transaction.commit()

@classmethod
def tearDownClass(cls):
    session.query(models.Stuff).delete() # delete planted stuff
    transaction.commit()

But i don't like deleting stuff with session.delete on my own, because i use many models and don't want track what i planted. I want something like

@classmethod
def tearDownClass(cls):
    session.clear() #delete all
    transaction.commit()

But session.close() or session.remove() will not affect committed data. So i seek some way to "cancel" setUpClass transaction.commit() like i don't plant anything.

I try nested transactions and savepoints but again they works only if data not committed yet.

Any pointers?

like image 390
Aristarhys Avatar asked Jul 30 '14 08:07

Aristarhys


People also ask

Is it possible to rollback after COMMIT?

COMMIT permanently saves the changes made by the current transaction. ROLLBACK undo the changes made by the current transaction. 2. The transaction can not undo changes after COMMIT execution.

Can we rollback after COMMIT in SQL Server?

Once SQL Server commits a transaction, you cannot run the ROLLBACK statement.

How do I rollback and COMMIT in SQL?

A COMMIT statement is used to save the changes on the current transaction is permanent. A Rollback statement is used to undo all the changes made on the current transaction. Once the current transaction is completely executed using the COMMIT command, it can't undo its previous state.

Can we execute COMMIT immediately after rollback?

I have confirmed that after rollback we cannot commit the same transaction. Make sure another transaction is not in waiting, else it will be committed. Also don't do anything with transaction in finally block. Always use finally block to close connection , data reader etc.


2 Answers

If you don't want things to be committed, simply don't call transaction.commit() :)

@classmethod
def setUpClass(cls):
    plant.StuffFactory() #plant stuff with FactoryBoy
    # you may possibly want to flush the session, so everything has proper IDs etc.
    DBSession.flush() 
    # let the transaction continue for the duration of the test

@classmethod
def tearDownClass(cls):
    # let the database make everything as if nothing happened
    transaction.rollback()

This would require that none of your code under test does explicit transaction management (transaction.commit() \ transaction.rollback() in application code), but that's a bad practice anyway:

As a general rule, the application should manage the lifecycle of the session externally to functions that deal with specific data. This is a fundamental separation of concerns which keeps data-specific operations agnostic of the context in which they access and manipulate that data.

Session Basics, SQLAlchemy Documentation (https://docs.sqlalchemy.org/en/13/orm/session_basics.html)

like image 184
Sergey Avatar answered Oct 16 '22 06:10

Sergey


In setUpClass() you could create a save point as:

sp = transaction.savepoint()

then in tearDownClass() you could simply use:

sp.rollback()

Hope this helps.

like image 41
Pankaj Sharma Avatar answered Oct 16 '22 06:10

Pankaj Sharma