[DB-SIG] Exeception Handling.
M.-A. Lemburg
mal at egenix.com
Fri Jul 4 14:34:08 CEST 2008
On 2008-07-04 14:22, M.-A. Lemburg wrote:
> 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.
FWIW: I'll be giving a talk on large-scale application design at
EuroPython 2008 next week which touches some of these design
principles.
Here's an older version:
http://www.egenix.com/library/presentations/#DevelopingLargeScaleApplicationsInPython
--
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