如何确保使用PyQt5.QtSql 关闭数据库连接?

0 投票
1 回答
24 浏览
提问于 2025-04-12 21:27

我写了一个应用程序,但总是出现这样的提示:

QSqlDatabasePrivate::removeDatabase: 连接 'qt_sql_default_connection' 仍在使用中,所有查询将停止工作。

我发现通过在执行时提供一个“连接名称”可以解决这个问题:

self.db_connection = QSqlDatabase.addDatabase("QSQLITE", self.db_connection_name)

我想确保我的所有数据库连接都能正确关闭,所以我使用了一个叫做 DatabaseConnectionMaker 的类,并结合 with 块来实现。

在下面的代码中,我已经这样做了,但现在我在一个小的可行性应用程序中不断收到以下输出,以确认 with 块的成功使用:

Table already exists and does not need to be created by dbConnection1.
QSqlDatabasePrivate::removeDatabase: connection 'dbConnection1' is still in use, all queries will cease to work.
Data inserted successfully by dbConnection1
Database connection dbConnection1 closed!!!

Process finished with exit code 0

我就是搞不清楚我哪里出错了。无论我尝试什么,QSqlDatabasePrivate::removeDatabase: 连接 'dbConnection1' 仍在使用中,所有查询将停止工作。 这个提示总是会出现。有人能帮我解答一下吗?

这是我的应用程序:

import sys

from PyQt5.QtSql import QSqlDatabase, QSqlQuery
from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QMainWindow, QApplication, 
QWidget


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
    
        self.db_name_main = "example.db"
    
        self.setGeometry(100, 100, 570, 600)
        self.setWindowTitle("Database Manipulation")
    
        # Create buttons
        create_database_button = QPushButton("Create Database ", self)
        create_database_button.clicked.connect(self.test_database_creation)
    
        central_widget = QWidget()
        layout = QVBoxLayout(central_widget)
        layout.addWidget(create_database_button)
    
        self.setCentralWidget(central_widget)
    
    def test_database_creation(self):
        with DatabaseConnectionMaker(self.db_name_main, "dbConnection1") as db_connection1:
            db_connection1.create_table("""CREATE TABLE IF NOT EXISTS example_table (
                   id INTEGER PRIMARY KEY,
                   name TEXT,
                   age INTEGER)""")
    
            db_connection1.insert_data("INSERT INTO example_table (name, age) "
                                       "VALUES (?, ?), (?, ?), (?, ?), (?, ?)",
                                       ["John", 30, "Alice", 25, "Bob", 35, "Eve", 28])
    
    
class DatabaseConnectionMaker:
    def __init__(self, db_name, db_connection_name):
        self.db_name = db_name
        self.db_connection = None
        self.db_connection_name = db_connection_name

    def connect(self):
        self.db_connection = QSqlDatabase.addDatabase("QSQLITE", self.db_connection_name)
        self.db_connection.setDatabaseName(self.db_name)
        if not self.db_connection.open():
            print("Failed to connect to database:", self.db_connection.lastError().text())
            return False
        return True

    def create_table(self, create_table_sql):
        query = QSqlQuery(self.db_connection)
        # Check if the table already exists
        if not self.table_exists():
            # If the table does not exist, execute the create_table_sql
            # query = QSqlQuery(self.db_connection)
            if not query.exec_(create_table_sql):
                print("Error creating table:", query.lastError().text())
            else:
                print(f"Table created successfully by {self.db_connection_name}")
                query.clear()
                del query
        else:
            print(f"Table already exists and does not need to be created by {self.db_connection_name}.")
            # Finished with the query, so clear it
            query.clear()
            del query

    def table_exists(self):
        tables = self.db_connection.tables()
        return "example_table" in tables

    def insert_data(self, insert_data_sql, values):
        query = QSqlQuery(self.db_connection)
        query.prepare(insert_data_sql)
        for i, value in enumerate(values):
            query.bindValue(i, value)
        if not query.exec_():
            print("Error inserting data:", query.lastError().text())
        else:
            print(f"Data inserted successfully by {self.db_connection_name}")
            query.clear()
            del query

    def close(self):
        self.db_connection.close()
        # QSqlDatabase.removeDatabase(self.db_connection.connectionName())
        QSqlDatabase.removeDatabase("dbConnection1")
        del self.db_connection

    def __enter__(self):
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
        print(f"Database connection {self.db_connection_name} closed!!!")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

1 个回答

0

关于removeDatabase的文档提到了C++,并指出了一些作用域的问题。结果发现,在Python中使用PyQt5.QtSql时,必须在self.db_connection.close()之后,和QSqlDatabase.removeDatabase("dbConnection1")之前放置del self.db_connection,这样一切就没问题了!!

我之前是在self.db_connection.close()和QSqlDatabase.removeDatabase("dbConnection1")之后才写del self.db_connection,这样做是错误的。

撰写回答