Question

I am working on some code that connects to an sqlite database. In the process of debugging said code, I am running into problems where I have hanging open connections to the database because some error prevented the execution of the close commands. Because db and c are defined within a function, I can't then find and close those objects from the command line. They are like orphaned connections or something, but in any case they prevent me from doing anything else with the database until I close and reopen my interactive console. Here's what it looks like:

def something()
    db=sqlite3.connect('mydatabase')
    c=db.cursor()

    somecode
    lots of different things happening in here
    this may have errors
    thus stopping execution

    db.commit()
    c.close()
    db.close()

I have tried a try/except clause with the final closing operations in a "finally" block, but that prevents exceptions from being raised back to the interactive output when I'm debugging, and things fail "silently" (maybe I'm not doing that part right?). Is there a better way to do this?

Was it helpful?

Solution

Generally it's good to use with...as statement:

with sqlite.connect(...) as db:
    with db.cursor() as c:
        ...

The with statement guarantees that close() will be called on an object either when with statement ends or exception is raised. And even when return or yield are called from the inside.

Read more here: http://docs.python.org/2/reference/compound_stmts.html#with

OTHER TIPS

As pointed out by Piotr, use of the with statement makes for much more efficient code, though it does not explicitly close the connection to the database, if this is what is desired by the user. This was found by a similar question here.

What using the with statement does do is run either the con.commit() method if the code block inside the with statement is executed without error; or the con.rollback() method if an exception is encountered.

Example from http://docs.python.org/2/library/sqlite3.html

import sqlite3

con = sqlite3.connect(":memory:")
con.execute("create table person (id integer primary key, firstname varchar unique)")

with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))

# If Successful, con.commit() is called automatically afterwards
# else con.rollback() is called after the with block finishes with an exception, 
# the exception is still raised and must be caught

try:
    with con:
        con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
    print "couldn't add Joe twice"

Note the use of the shortcut method con.execute() which is a method of the database connection object. This implicitly creates the cursor object for you and returns the result, and so requires even less code to be written.

To clean up resources, use only finally:

db = sqlite.connect(...)
try:
    ...
    c = db.cursor()
    try:
        ...
    finally:
        c.close()
    ...
finally:
    db.close()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top