Python 中如何正确地关闭内部 pysqlite 连接

67 阅读3分钟

在 Python 中,您可能需要在对象的生命周期中维护一个内部数据库连接。在程序结束时,您需要提交并关闭该连接。最直接的方法是使用显式的 close 方法,但这可能会有些麻烦,尤其是在调用代码中可能发生异常时。

考虑使用 del 方法进行关闭,但经过网上的一些查询,您可能会有所顾虑。del 是否是一种有效的用法模式?您能确保 del 中的内部资源能被正确释放吗?

在某个讨论中,有人提出了类似的问题,但没有找到令人满意的答案。您不想使用显式的 close 方法,使用 with 也不是一种选择,因为您的对象并不是像打开-操作-关闭那样简单,而是作为另一个更大的对象的成员保留,该对象在 GUI 中运行时使用它。

C++ 有一个工作良好的析构函数,在其中可以安全地释放资源,因此您可以想象 Python 中也应该有类似的约定。但事实并非如此,许多社区成员反对使用 del。那么,有什么替代方法呢?

2、解决方案

1、使用 with 语句

with 语句可以帮助您在一个上下文管理器中管理资源,并在上下文结束后自动释放它们。这对于需要在对象的生命周期中维护一个连接非常有用。

以下是使用 with 语句关闭内部 pysqlite 连接的示例:

from contextlib import contextmanager
import sqlite3

@contextmanager
def connect(db_path):
    """上下文管理器用于连接到 SQLite 数据库"""
    connection = sqlite3.connect(db_path)
    try:
        yield connection
    finally:
        connection.close()

def main():
    with connect('my_database.db') as connection:
        # 使用连接来执行查询或其他操作
        cursor = connection.cursor()
        cursor.execute("SELECT * FROM users")
        results = cursor.fetchall()
        for row in results:
            print(row)

if __name__ == "__main__":
    main()

2、使用模块

您还可以创建一个连接模块,因为模块在整个应用程序中保持同一个对象,并使用 atexit 模块注册一个函数来关闭它。

以下是使用模块和 atexit 模块关闭内部 pysqlite 连接的示例:

import sqlite3
import atexit

# 创建一个模块来管理连接
connection = None

def get_connection():
    """获取数据库连接"""
    global connection
    if not connection:
        connection = sqlite3.connect('my_database.db')
    return connection

# 注册一个函数来关闭连接
def close_connection():
    """关闭数据库连接"""
    global connection
    if connection:
        connection.close()

atexit.register(close_connection)

def main():
    # 获取并使用连接
    connection = get_connection()
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM users")
    results = cursor.fetchall()
    for row in results:
        print(row)

if __name__ == "__main__":
    main()

3、使用 del 方法

如果以上两种方法都不适合您,您也可以使用 del 方法来关闭内部 pysqlite 连接。但是,请注意,del 方法在 Python 中并不是一个可靠的方式来释放资源,因为它可能会在不恰当的时候被调用。

以下是使用 del 方法关闭内部 pysqlite 连接的示例:

import sqlite3

class SqlConnection:
    def __init__(self, db_path):
        self.connection = sqlite3.connect(db_path)

    def __del__(self):
        """析构函数以关闭连接"""
        self.connection.close()

def main():
    # 创建一个 SqlConnection 对象
    connection = SqlConnection('my_database.db')

    # 使用连接来执行查询或其他操作
    cursor = connection.connection.cursor()
    cursor.execute("SELECT * FROM users")
    results = cursor.fetchall()
    for row in results:
        print(row)

# 在 main 函数结束后,SqlConnection 对象将被销毁,并调用 __del__ 方法来关闭连接。

if __name__ == "__main__":
    main()

注意:在使用 del 方法时,您需要小心地处理循环引用,因为它们可能导致内存泄漏。

无论是使用 with 语句、模块还是 del 方法,您都可以选择最适合您应用程序的方法来关闭内部 pysqlite 连接。