I have some code to update a database table that looks like
try
{
db.execute("BEGIN");
// Lots of DELETE and INSERT
db.execute("COMMIT");
}
catch (DBException&)
{
db.execute("ROLLBACK");
}
I'd like to wrap the transaction logic in an RAII class so I could just write
{
DBTransaction trans(db);
// Lots of DELETE and INSERT
}
but how would I write the destructor for it?
Use following:
transaction tr(db);
...
tr.commit();
When tr.commit()
completes it sets the state to "commit done" and destructor does nothing,
otherwise it rollbacks.
Checking for exception is bad idea, consider:
transaction tr(db);
...
if(something_wrong)
return; // Not throw
...
tr.commit();
In this case you probably expect rather rollback then commit but commit would be done.
Edit: but if you still want it badly, take a look on std::uncaught_exception()
but read this first http://www.gotw.ca/gotw/047.htm
You might use the following logic:
By removing the exception handling, you are crippling your RAII.
The code should be
try
{
DBTransaction trans(db) ;
// Lots of DELETE and INSERT
// should one fail, a DBTransactionRollback exception will be thrown
trans.commit() ;
}
catch(const DBTransactionRollback & e)
{
// If really needed, you could extract failure information from "e"
}
The differences with your original code are what motivated my answer:
There is nothing needed in the "catch" : The destructor will assume an automatic rollback unless the commit() method was called with success (which could, for example, set some private boolean member of DBTransaction to true). The catch is where the code will continue, assuming the transaction failed.
You should create a dedicated exception (I named it DBTransactionRollback) to throw the moment something fails in one of your commands. Thus, the catch will only catch transaction rollback-motivated exception, and not other exceptions (like STL, etc.)
The use of the exception mechanism enables you to put your code in multiple functions, called from this try/catch block of code, without having to deal with boolean returns and other error code returns.
Hope this answers your question.
Easiest way I can think of would be to set a private member variable in the class in the exception, and test it / perform the appropriate action in the destructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With