On Feb 10, 2016, at 8:06 PM, Frank Millman <fr...@chagford.com> wrote:
> 
> "Israel Brewster"  wrote in message 
> news:92d3c964-0323-46ee-b770-b89e7e7e6...@ravnalaska.net...
> 
>> I am working on implementing a Python DB API module, and am hoping I can get 
>> some help with figuring out the workflow of handling transactions. In my 
>> experience (primarily with
>> psycopg2) the workflow goes like this:
>> 
>> - When you open a connection (or is it when you get a cursor? I *think* it 
>> is on opening a connection), a new transaction is started
>> - When you close a connection, an implicit ROLLBACK is performed
>> - After issuing SQL statements that modify the database, you call commit() 
>> on the CONNECTION object, not the cursor.
>> 
>> My primary confusion is that at least for the DB I am working on, to 
>> start/rollback/commit a transaction, you execute the appropriate SQL 
>> statement (the c library I'm using doesn't
>> have any transactional commands, not that it should). However, to execute 
>> the statement, you need a cursor. So how is this *typically* handled? Does 
>> the connection object keep an > internal cursor that it uses to manage 
>> transactions?
>> 
>> I'm assuming, since it is called on the connection, not the cursor, that any 
>> COMMIT/ROLLBACK commands called affect all cursors on that connection. Is 
>> that correct? Or is this DB
>> specific?
>> 
>> Finally, how do other DB API modules, like psycopg2, ensure that ROLLBACK is 
>> called if the user never explicitly calls close()?
> 
> Rather than try to answer your questions point-by-point, I will describe the 
> results of some investigations I carried out into this subject a while ago.
> 
> I currently support 3 databases, so I use 3 DB API modules - 
> PostgreSQL/psycopg2, Sql Server/pyodbc, and sqlite3/sqlite3. The following 
> applies specifically to psycopg2, but I applied the lessons learned to the 
> other 2 as well, and have had no issues.
> 
> A connection has 2 possible states - 'in transaction', or 'not in 
> transaction'. When you create the connection it starts off as 'not'.
> 
> When you call cur.execute(), it checks to see what state it is in. If the 
> state is 'not', it silently issues a 'BEGIN TRANSACTION' before executing 
> your statement. This applies for SELECT as well as other statements.
> 
> All subsequent statements form part of the transaction, until you issue 
> either conn.commit() or conn.rollback(). This performs the required action, 
> and resets the state to 'not'.
> 
> I learned the hard way that it is important to use conn.commit() and not 
> cur.execute('commit'). Both succeed in committing, but the second does not 
> reset the state, therefore the next statement does not trigger a 'BEGIN', 
> with possible unfortunate side-effects.

Thanks - that is actually quite helpful. So the way I am looking at it now is 
that the connection would have an internal cursor as I suggested. From your 
response, I'll add a "state" flag as well. If the state flag is not set when 
execute is called on a cursor, the cursor itself will start a transaction and 
set the flag (this could happen from any cursor, though, so that could 
potentially cause a race condition, correct?). In any case, there is now a 
transaction open, until such a time as commit() or rollback() is called on the 
connection, or close is called, which executes a rollback(), using the 
connection's internal cursor.

Hopefully that all sounds kosher. 

> 
> HTH
> 
> Frank Millman
> 
> 
> -- 
> https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to