You are just making my point with that OOP mess (sorry). You are not using RAII to finish (meaning cleanup or rollback) the transaction.
What we want actually executed in the end (in terms of control flow - not necessarily what we would be willing to code), is something like the following clean procedural code.
do_some_foo():
start_transaction()
r = do_thing_A()
if r == CONFLICT:
rollback()
return r
r = do_thing_B()
if r == CONFLICT:
rollback()
return r
commit()
return OK