Advice on mixing transactions and exceptions

5 views
Skip to first unread message

DaveS

unread,
Nov 5, 2005, 1:06:53 PM11/5/05
to TurboGears
I'm trying to figure out how to structure my code so transactions do
the right thing when exceptions are raised. So far I've got

def update(self):
hub.begin()
self.modify_database()
if i_dont_like_things:
hub.rollback()
else:
hub.commit()
hub.end()

Is there any way to have a rollback happend automatically if
modify_database raises an exception? Or do I need to wrap everything
in a try/except to guarantee a rollback (and I assume I would also need
a hub.end() in there as well).

I'm thinking of the feature in some systems where you aquire a
transaction object which will automatically do a rollback if it goes
out of scope without a commit. Somthing like:

trans = hub.begin()
do_work()
trans.commit()

--
DS

Kevin Dangoor

unread,
Nov 5, 2005, 1:42:52 PM11/5/05
to turbo...@googlegroups.com
There's been at least a couple of threads about automatically doing
transactions at the request boundaries in some form. The idea will
probably be something along the lines of having your methods wrapped
in a transaction unless you tell expose not to do so.

This will easily handle rolling back if an exception occurs within the
code. There's a good chance this will arrive in 0.9.

Kevin

Jeff Watkins

unread,
Nov 5, 2005, 10:31:45 PM11/5/05
to turbo...@googlegroups.com

On 5 Nov, 2005, at 1:06 pm, DaveS wrote:
> I'm trying to figure out how to structure my code so transactions do
> the right thing when exceptions are raised. So far I've got
>
> def update(self):
> hub.begin()
> self.modify_database()
> if i_dont_like_things:
> hub.rollback()
> else:
> hub.commit()
> hub.end()
>
> Is there any way to have a rollback happend automatically if
> modify_database raises an exception? Or do I need to wrap everything
> in a try/except to guarantee a rollback (and I assume I would also
> need
> a hub.end() in there as well).

You might consider writing your code like this:

def update(self):
try:
hub.begin()
# do some stuff
hub.commit()
finally:
hub.rollback()

From what I've seen, rolling back a transaction after committing
won't cause problems. This way, no matter how your code exits the
block, the transaction will be committed or rolled back. This doesn't
force you to catch any exceptions.

--
Jeff Watkins
http://newburyportion.com/

In the USDA study [of the meat packing industry conducted in 1996]
78.6 percent of the ground beef contained microbes that are spread
primarily by fecal material. The medical literature on the causes of
food poisoning is full of euphemisms and dry scientific terms:
coliform levels, aerobic plate counts, sorbitol, MacConkey agar, and
so on. Behind them lies a simple explanation for why eating a
hamburger can now make you seriously ill: There is shit in the meat.
-- Eric Schlosser, Fast Food Nation


Ian Bicking

unread,
Nov 5, 2005, 10:39:21 PM11/5/05
to turbo...@googlegroups.com
Jeff Watkins wrote:
>
>
> On 5 Nov, 2005, at 1:06 pm, DaveS wrote:
>
>> I'm trying to figure out how to structure my code so transactions do
>> the right thing when exceptions are raised. So far I've got
>>
>> def update(self):
>> hub.begin()
>> self.modify_database()
>> if i_dont_like_things:
>> hub.rollback()
>> else:
>> hub.commit()
>> hub.end()
>>
>> Is there any way to have a rollback happend automatically if
>> modify_database raises an exception? Or do I need to wrap everything
>> in a try/except to guarantee a rollback (and I assume I would also need
>> a hub.end() in there as well).
>
>
> You might consider writing your code like this:
>
> def update(self):
> try:
> hub.begin()
> # do some stuff
> hub.commit()
> finally:
> hub.rollback()

More proper would be:

hub.begin()
try:
do stuff
except:
hub.rollback()
raise
else:
hub.commit()


Though of course in the "else:" block you could commit or rollback based
on some flag, if you didn't want to automatically commit.

--
Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org

DaveS

unread,
Nov 6, 2005, 11:57:16 AM11/6/05
to TurboGears
>
> More proper would be:
>
> hub.begin()
> try:
> do stuff
> except:
> hub.rollback()
> raise
> else:
> hub.commit()
>
>
> Though of course in the "else:" block you could commit or rollback based
> on some flag, if you didn't want to automatically commit.
>
> --
> Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org

That looks like nice and simple - I like it.
No one seems to be including hub.end() in their examples. I wondered
if this step is optional or if bad things would happen if I skiped it.

--
DS

Reply all
Reply to author
Forward
0 new messages