如果我不关闭Python SQLite中的数据库连接怎么办


74

我正在做这样的事情...

conn = sqlite3.connect(db_filename)

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

with自动提交更改。但是文档对关闭连接一无所知。

实际上,我可以conn在以后的语句(已测试)中使用。因此,似乎上下文管理器没有关闭连接。

我是否必须手动关闭连接。如果我打开它怎么办?

编辑

我的发现:

  • 我已经测试并确认了上下文管理器中的连接未关闭。在之后__exit__,上下文管理器仅通过执行以下操作来提交更改:conn.commit()
  • with conn并且with sqlite3.connect(db_filename) as conn相同,因此使用其中任何一个仍将保持连接活动
  • with 语句不会创建新的作用域,因此在with套件内创建的所有变量都可以在其外部访问
  • 最后,您应该手动关闭连接

1
如果将其保持打开状态,它将保持打开状态,直到超出范围并收集垃圾为止。到那时,它可能已经安全关闭(我相信sqlite3是可以做到的)。但要安全起见,总比后悔好。当您不再使用连接时,请关闭它们。
Avaris'3

1
很高兴看到有6个代表的SO用户回来并反击他们认为没有回答问题的要求答案。那里有+1。
Droogans 2012年

Answers:


42

在回答如果您不关闭SQLite数据库会发生什么的特定问题时,答案很简单,适用于以任何编程语言使用SQLite。当连接由代码显式关闭或由程序退出隐式关闭时,所有未完成的事务都会回滚。(回滚实际上是由下一个打开数据库的程序完成的。)如果没有未完成的事务打开,则什么也不会发生。

这意味着您不必担心总是在进程退出之前关闭数据库,而您应该注意事务以确保启动它们并在适当的时间提交。


7
像Web应用程序一样,长时间运行的进程在退出时没有隐式关闭,因为没有退出。
乔纳森·哈特利

14

您在这里有一个潜在的潜在问题,但是了解sqlite的运作方式也很重要:

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

数据正确性而言,您只需要担心事务,而不用担心打开句柄。sqlite仅在transaction(*)或语句执行内的数据库上拥有锁。

但是,在资源管理方面,例如,如果您打算删除sqlite文件或使用太多连接,则可能会用完文件描述符,那么您也确实关心打开事务外连接。

有两种关闭连接的方法:要么.close()显式调用,之后仍然有一个句柄但不能使用它;或者让连接超出范围并进行垃圾回收。

如果必须关闭连接,则根据Python的座右铭“显式优于隐式显式地关闭它。

如果仅检查代码的副作用,则可以接受保留对连接的引用的最后一个变量超出范围,这是可以接受的,但请记住,异常会捕获堆栈,因此会引用该堆栈。如果您传递异常,则连接寿命可以任意延长。

警告,默认情况下,sqlite使用“延迟”事务,即,仅在执行语句时才开始事务。在上面的示例中,事务从3到4,而不是从2到4。


1
我猜想使用内存数据库(sqlite3.connect(':memory:'))时资源管理部分不适用?我希望在这种情况下不使用任何文件描述符。
Jaanus Varus

1
@JaanusVarus在使用:memory:数据库时确实没有分配文件描述符。我毕竟不能确定内部资源:)请注意,内存数据库在关闭最后一个连接时会被删除,因此对于OP用例和:memory:,它们必须至少保留1个连接打开以保留数据。
迪马·提斯内克

9

这是我使用的代码。在ConnectionCursor会自动关闭感谢contextlib.closing()。在Connection将自动提交多亏了上下文管理。

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)

1
最内在的意义是with什么?要释放一些内存?如果不使用该上下文管理器,会遇到什么问题?如果不返回,就不只是从函数中返回cursor
Markus von Broady

4

您可以使用with如下代码:

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()
  • 连接
  • 开始交易
  • 创建一个数据库游标
  • 执行操作并返回结果
  • 关闭光标
  • 提交/回滚事务
  • 关闭连接

无论是在喜事还是例外情况下,一切都安全


1
这很棒。请注意,如果您执行的操作不会返回任何内容(例如插入或更新),则cur.fetchall()只会返回一个空列表。
–storm_m2138

0

使用连接后,您的版本将conn纳入范围。

例:

您的版本

    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

新版本

    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)

18
with不会创建新范围。 在这两种情况下conn都将可用with
Avaris'3

-1

为了管理与数据库的连接,我通常会这样做,

# 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

这样做,我确定该连接已明确关闭。


5
不会在抛出异常的情况下关闭连接
JurkoGospodnetić17-10-2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.