Default scope of variables
Frank Millman
frank at chagford.com
Tue Jul 9 03:35:34 EDT 2013
"Chris Angelico" <rosuav at gmail.com> wrote in message
news:CAPTjJmqkmFd4-Jpugr-vubuB6riBV6K_Mwnxc_U3CVaBr_Wgbg at mail.gmail.com...
> On Tue, Jul 9, 2013 at 4:08 PM, alex23 <wuwei23 at gmail.com> wrote:
>> On 9/07/2013 3:07 PM, Chris Angelico wrote:
>>>
>>> The subtransactions are NOT concepted as separate transactions. They
>>> are effectively the database equivalent of a try/except block.
>>
>>
>> Sorry, I assumed each nested query was somehow related to the prior
>> one. In which case, I'd probably go with Ethan's suggestion of a
>> top-level transaction context manager with its own substransaction
>> method.
>
> Yeah, that would probably be the best option in this particular
> instance. Though I do still like the ability to have variables shadow
> each other, even if there's a way around one particular piece of code
> that uses the technique.
>
I have been following this sub-thread with interest, as it resonates with
what I am doing in my project.
In my case, one update can trigger another, which can trigger another, etc.
It is important that they are treated as a single transaction. Each object
has its own 'save' method, so there is not one place where all updates are
executed, and I found it tricky to control.
I came up with the following context manager -
class DbSession:
"""
A context manager to handle database activity.
"""
def __init__(self):
self.conn = None
self.no_connections = 0
self.transaction_active = False
def __enter__(self):
if self.conn is None:
self.conn = _get_connection() # get connection from pool
self.conn.cur = self.conn.cursor()
# all updates in same transaction use same timestamp
self.conn.timestamp = datetime.now()
self.no_connections += 1
return self.conn
def __exit__(self, type, exc, tb):
if type is not None: # an exception occurred
if self.transaction_active:
self.conn.rollback()
self.transaction_active = False
self.conn.release() # return connection to pool
self.conn = None
return # will reraise exception
self.no_connections -= 1
if not self.no_connections:
if self.transaction_active:
self.conn.commit()
self.transaction_active = False
self.conn.cur.close()
self.conn.release() # return connection to pool
self.conn = None
All objects created within a session share a common DbSession instance.
When any of them need any database access, whether for reading or for
updating, they execute the following -
with db_session as conn:
conn.transaction_active = True # this line must be added if
updating
conn.cur.execute(__whatever__)
Now it 'just works'. I don't have the need for save-points - either all
updates happen, or none of them do.
Frank Millman
More information about the Python-list
mailing list