106

I am doing something like this...

conn = sqlite3.connect(db_filename)

with conn:
    cur = conn.cursor()
    cur.execute( ... )

with automatically commits the changes. But the docs say nothing about closing the connection.

Actually I can use conn in later statements (which I have tested). Hence it seems that the context manager is not closing the connection.

Do I have to manually close the connection. What if I leave it open?

EDIT

My findings:

  • The connection is not closed in the context manager, I have tested and confirmed it. Upon __exit__, the context manager only commits the changes by doing conn.commit()
  • with conn and with sqlite3.connect(db_filename) as conn are same, so using either will still keep the connection alive
  • with statement does not create a new scope, hence all the variables created inside the suite of with will be accessible outside it
  • Finally, you should close the connection manually
treecoder
  • 43,129
  • 22
  • 67
  • 91
  • 2
    If you leave it open, it stays open until it goes out of scope and garbage collected. At that point it _might be_ safely closed (and I believe `sqlite3` does that). But better to be safe than sorry. Close your connections when you will no longer use them. – Avaris Mar 05 '12 at 06:10
  • 2
    Good to see an SO user with 6 rep come back and counter claim answers they feel aren't answering the question. A big +1 there. – yurisich Mar 05 '12 at 12:49

6 Answers6

62

In answer to the specific question of what happens if you do not close a SQLite database, the answer is quite simple and applies to using SQLite in any programming language. When the connection is closed explicitly by code or implicitly by program exit then any outstanding transaction is rolled back. (The rollback is actually done by the next program to open the database.) If there is no outstanding transaction open then nothing happens.

This means you do not need to worry too much about always closing the database before process exit, and that you should pay attention to transactions making sure to start them and commit at appropriate points.

Roger Binns
  • 3,203
  • 1
  • 24
  • 33
18

You have a valid underlying concern here, however it's also important to understand how sqlite operates too:

1. connection open
    2. transaction started
        3. statement executes
    4. transaction done
5. connection closed

in terms of data correctness, you only need to worry about transactions and not open handles. sqlite only holds a lock on a database inside a transaction(*) or statement execution.

however in terms of resource management, e.g. if you plan to remove sqlite file or use so many connections you might run out of file descriptors, you do care about open out-of-transaction connections too.

there are two ways a connection is closed: either you call .close() explicitly after which you still have a handle but can't use it, or you let the connection go out of scope and get garbage-collected.

if you must close a connection, close it explicitly, according to Python's motto "explicit is better than implicit."

if you are only checking code for side-effects, letting a last variable holding reference to connection go out of scope may be acceptable, but keep in mind that exceptions capture the stack, and thus references in that stack. if you pass exceptions around, connection lifetime may be extended arbitrarily.

caveat programmator, sqlite uses "deferred" transactions by default, that is the transaction only starts when you execute a statement. In the example above, transaction runs from 3 to 4, rather than from 2 to 4.

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
  • 2
    I guess the resource management part doesn't apply when an in-memory database is used (`sqlite3.connect(':memory:')`)? I'd expect no file descriptors to be used in that scenario. – Jaanus Varus May 27 '20 at 13:43
  • 1
    @JaanusVarus indeed there are no file descriptors allocating when working with `:memory:` databases. I can't be sure about internal resources though, I mean, memory after all :) Note that in-memory databases are deleted when last connection is closed, so for the OP use-case and `:memory:`, they'd have to keep at least 1 connection open to keep the data around. – Dima Tisnek May 28 '20 at 01:33
18

You can use a with block like this:

from contextlib import closing
import sqlite3

def query(self, db_name, sql):
    with closing(sqlite3.connect(db_name)) as con, con,  \
            closing(con.cursor()) as cur:
        cur.execute(sql)
        return cur.fetchall()
  • connects
  • starts a transaction
  • creates a db cursor
  • performs the operation and returns the results
  • closes the cursor
  • commits/rolls-back the transaction
  • closes the connection

all safe in both happy and exceptional cases

  • 2
    This is great. Note that if you are executing something that **doesn't return anything** such as an insert or update, **cur.fetchall()** will just return an empty list. – storm_m2138 Jun 28 '18 at 18:41
  • 1
    this should be more prominent in sqlite docs. Annoyed I was not aware this should be standard practice. big thanks. – CodingMatters Jan 20 '21 at 22:47
16

This is the code that I use. The Connection and the Cursor will automatically close thanks to contextlib.closing(). The Connection will automatically commit thanks to the context manager.

import sqlite3
import contextlib

def execute_statement(statement):
    with contextlib.closing(sqlite3.connect(path_to_file)) as conn: # auto-closes
        with conn: # auto-commits
            with contextlib.closing(conn.cursor()) as cursor: # auto-closes
                cursor.execute(statement)
stackoverflowuser2010
  • 38,621
  • 48
  • 169
  • 217
  • 5
    What's the point of the innermost `with`? To free some memory? What kind of problems can you run into if you don't use that context manager? Wouldn't just returning from the function be an equivalent if you don't return the `cursor`? – Markus von Broady Nov 24 '19 at 13:20
  • 1
    @MarkusvonBroady Explicitly closing the `Cursor` object is good practice to prevent operation errors. [See this post](https://stackoverflow.com/questions/53270520/how-to-know-which-process-is-responsible-for-a-operationalerror-database-is-lo/53470118#53470118) for more information. – howdoicode Sep 06 '21 at 13:59
  • 1
    @howdoicode I don't see any source there for your claim about a good practice. I'm open-minded to the idea, but also skeptical. A decade will soon pass since OP asked the question and we still don't have a reputable source on what are the good practices in the subject or an in-depth explanation **why**. I treat quoting the Zen of Python on explicitness with a grain of salt, as it's not idiomatic in Python to explicitly deallocate dynamic data or mark an object as unusable. That's what GC and `__del__` are for. Dima's 2nd last paragraph is disturbing, because it suggests a flaw of the language. – Markus von Broady Sep 06 '21 at 15:19
  • Sorry for a bit of necro-posting, but I also don't understand the of either outermost or innermost context statement. Both cursors and connections are closed automatically when they go out of scope, so if you're not returning the cursor, only the auto-transaction context block is necessary, no? – thegreatemu Feb 08 '22 at 20:32
  • I skip the last `with` and instead directly do `conn.execute()` inside the second `with` and a `try`. Official Python documentation in [§ How to use connection shortcut methods](https://docs.python.org/3/library/sqlite3.html#how-to-use-connection-shortcut-methods) calls out _code can be written more concisely because you don’t have to create the (often superfluous) Cursor objects explicitly_. [§ How to use the connection context manager](https://docs.python.org/3/library/sqlite3.html#how-to-use-the-connection-context-manager) is also a recommended read under _§ How-to guides_. – legends2k Sep 01 '22 at 07:13
1

Your version leaves conn in scope after connection usage.

EXAMPLE:

your version

    conn = sqlite3.connect(db_filename) #DECLARE CONNECTION OUT OF WITH BLOCK

    with conn:                          #USE CONNECTION IN WITH BLOCK
        cur = conn.cursor()
        cur.execute( ... )

   #conn variable is still in scope, so you can use it again

new version

    with sqlite3.connect(db_filename) as conn:  #DECLARE CONNECTION AT START OF WITH BLOCK
        cur = conn.cursor()
        cur.execute( ... )   

   #conn variable is out of scope, so connection is closed 
   # MIGHT BE IT IS NOT CLOSED BUT WHAT  Avaris SAID!
   #(I believe auto close goes for with block)
Rafael Barros
  • 2,738
  • 1
  • 21
  • 28
elrado
  • 4,960
  • 1
  • 17
  • 15
  • 23
    [`with` does not create new scope.](http://stackoverflow.com/questions/6432355/variable-defined-with-with-statement-available-outside-of-with-block) `conn` will be available after the `with` in both cases. – Avaris Mar 05 '12 at 05:43
-1

For managing a connection to a database I usually do this,

# query method belonging to a DB manager class

def query (self, sql):
    con = sqlite3.connect(self.dbName)
    with con:
        cur = con.cursor()
        cur.execute(sql)
        res = cur.fetchall()
    if con:
        con.close()

    return res

doing so, I'm sure that the connection is explicitly closed.

Guido
  • 76
  • 3