"Chris Angelico" <ros...@gmail.com> wrote in message news:captjjmqkmfd4-jpugr-vubub6ribv6k_mwnxc_u3cvabr_w...@mail.gmail.com... > On Tue, Jul 9, 2013 at 4:08 PM, alex23 <wuwe...@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 -- http://mail.python.org/mailman/listinfo/python-list