[DB-SIG] Exeception Handling.

M.-A. Lemburg mal at egenix.com
Fri Jul 4 14:22:38 CEST 2008


On 2008-07-04 14:03, Heston James - Cold Beans wrote:
>> I'd put the whole transaction code into a try-except:
>>
>> try:
>>      # Start of transaction
>>      ... do stuff ...
>> except Exception:
>>      self.datasource.rollback()
>>      raise
>> else:
>>      self.datasource.commit()
>>
>> This assures that a successful execution of your code results in
>> the transaction to be committed. In case something goes wrong,
>> the transaction is rolled back and the error reraised so that you
>> can process it at some higher level.
>>
>> I'd really appreciate your advice on this, I'm relatively new to the world
>> of db implementation using the dbapi and want to make this as water tight
> as
>> possible.
> 
> Hi Marc-Andre,
> 
> Thank you for your advice, that's really very helpful. I'd like to extend
> this question a little if you don't mind. Let's say for instance that the
> persistence of an object isn't just in the database but also on the file
> system. And for instance this is done like so:
> 
>             # Open the file object in write binary mode.
>             message = open("/files/%s/%s" % (self.message_id, self.name),
> "wb")
> 
>            	# Write the binary to the file.
>             message.write(base64.decodestring(self.binary_data))
> 
>             # Close the file object.
>             message.close()
> 
> Now, within my object let's say that I have a method such as save() which I
> need to save the object to the database (using the code we've already
> discussed) and also run that file save code to write it to the file system.
> 
> How would you transaction ALL of this? So if either the file save or the
> database persist fails then it rolls them both back? So I don't end up with
> a file without a DB entry or a DB entry without a file?

If you want to do this right, you need a transaction manager and
then have to use two-phase commits to commit the work on all
resources. Depending on the needs and requirements, this can be
anything from hard to undoable (not all resources support two-phase
commit).

> I'd be interested to know A) how would you arrange a try/except block to
> handle this, and B) would you put this method in the bean or abstract it out
> into a service layer and have two methods in the bean, one for the file save
> and one for the database save and wrap those in a transaction at a higher
> level?

I usually write manager classes for such things which buffer the output
and only write to the file system if .commit() is called. A .rollback()
would just clear the buffers.

If done right, you can also add two-phase commit logic to such a manager
class.

BTW: The DB-API has recently received an update which defines a
two-phase extension for those backends which support this. Have
a look at PEP 249 near the end of the page.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jul 04 2008)
 >>> Python/Zope Consulting and Support ...        http://www.egenix.com/
 >>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
 >>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________
2008-07-07: EuroPython 2008, Vilnius, Lithuania             2 days to go

:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::


    eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
     D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
            Registered at Amtsgericht Duesseldorf: HRB 46611


More information about the DB-SIG mailing list