QSqlDatabase:如何避免 'qt_sql_default_connection' still in use & duplicate connection 相关警告?

QSqlDatabase: How to avoid 'qt_sql_default_connection' still in use & duplicate connection related warning?

抱歉,如果这是一个微不足道的问题,但我一直在尝试创建一个小的 .ui,它使用 QSQLITE 作为数据库并使用 QTableView以在默认数据库文件上显示 4 列为例。

我调试了各个方面的问题,更改了SQL的逻辑操作,并以更简单的方式重构了构造函数,但错误仍然存​​在。

完成所有参数设置后出现此错误:

QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.

QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.

我查看了几个描述此错误的来源,例如 this source, this other source. Also was useful but still nothing happens. Official documentation suggests a "wrong" and "right" way to do that here。但错误仍然存​​在。在所有这些不同的选项之后,我将代码恢复为更简洁的方式,我希望有人能阐明这个问题。

代码片段下方:

mainwindow.h

private:
    QString temporaryFolder;
    dataInfo *mNewDatabaseImages;
    QSqlTableModel *mNewTableImages;

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    temporaryFolder = "/home/to/Desktop/tempDBFolder/tmp.db";
    QFile dbRem(temporaryFolder);
    dbRem.remove();
    mNewDatabaseImages = new dataInfo(this);
    mNewDatabaseImages->initDataBase(temporaryFolder);
    mNewDatabaseImages->confDataBase();
    mNewTableImages = new QSqlTableModel(this, mNewDatabaseImages->getDatabase());
    mNewTableImages->setTable("leftCamTable");
    mNewTableImages->select();
    ui->bookMarkTableView->setModel(mNewTableImages);
    ui->bookMarkTableView->showColumn(true);
}

datainfo.h

#ifndef DATAINFO_H
#define DATAINFO_H
#include <QObject>
#include <QSqlDatabase>
#include "imageparam.h"

class dataInfo : public QObject
{
    Q_OBJECT
public:
    explicit dataInfo(QObject *parent = nullptr);
    bool initDataBase(const QString &nameDB);
    bool confDataBase();
    bool addItem(ImageParam* imageItem);
    QSqlDatabase getDatabase();
private:
    QString mError;
    QSqlDatabase mDBImages;
};
#endif // DATAINFO_H

datainfo.cpp

#include "datainfo.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QVariant>
#include <QMessageBox>

#define CREATE_TABLE \
    " CREATE TABLE IF NOT EXISTS imageTable" \
    " (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" \
    " path1 TEXT NOT NULL" \
    " path2 TEXT NOT NULL" \
    " imageA BLOB NOT NULL" \
    " imageB BLOB NOT NULL)"

dataInfo::dataInfo(QObject *parent) : QObject(parent)
{}

bool dataInfo::initDataBase(const QString &nameDB)
{
    mDBImages = QSqlDatabase::addDatabase("QSQLITE");
    mDBImages.setDatabaseName(nameDB);
    bool ok = mDBImages.open();
    if(!ok) {
        mError = mDBImages.lastError().text();
        qDebug() << mError;
    }
    return ok;
}

bool dataInfo::confDataBase()
{
    QSqlQuery qry;
    bool ok = qry.exec(CREATE_TABLE);
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

bool dataInfo::addItem(ImageParam *imageItem)
{
    QSqlQuery qry;
    qry.prepare("INSERT INTO imageTable (path1, path2, imageA, imageB)" \
                " VALUES (?,?,?,?)");
    qry.addBindValue(imageItem->path1());
    qry.addBindValue(imageItem->path2());
    qry.addBindValue(imageItem->image1());
    qry.addBindValue(imageItem->image2());
    bool ok = qry.exec();
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

QSqlDatabase dataInfo::getDatabase()
{
    return mDBImages;
}

我还查看了 this post that suggested to set a name to the databse first but I already do that in the function initDataBase(const QString &nameDB). Here the post 建议的程序,如下所示:

db->setDatabaseName("name");
if(!db->open()) {
    qDebug() << "Error opening ";
    return false;
}

请阐明可能的解决方案。

简答

  • 你应该指定你想要运行你的QSqlQuery上的数据库,否则他们会运行上默认的数据库。您可以在 QSqlQuery 的构造函数中使用

    指定数据库

    QSqlQuery query(QSqlDatabase::database("my-db"));

  • 您正在保留 QSqlDatabase 的副本作为您的 dataInfo class 的成员,这将阻止它正常关闭。相反,只需在需要时使用静态 QSqlDatabase::database("name")

    auto db = QSqlDatabase::database("my-db");

详情

为 QSqlQuery 提供正确的数据库

更改 QSqlQuery 的所有用途。例如 confDataBase:

bool dataInfo::confDataBase()
{
    // Explicitly provide your database to the query
    // Otherwise the default database is used
    QSqlQuery qry(getDatabase());
    bool ok = qry.exec(CREATE_TABLE);
    if(!ok) {
        mError = qry.lastError().text();
    }
    return ok;
}

不保留 QSqlDatabase 属性

来自文档:

Warning: It is highly recommended that you do not keep a copy of the QSqlDatabase around as a member of a class, as this will prevent the instance from being correctly cleaned up on shutdown. If you need to access an existing QSqlDatabase, it should be accessed with database(). If you chose to have a QSqlDatabase member variable, this needs to be deleted before the QCoreApplication instance is deleted, otherwise it may lead to undefined behavior.

改为将数据库名称存储在 class 中,并将 getDatabase 更改为

dataInfo.cpp

bool dataInfo::initDataBase(const QString &nameDB)
{
    // Save database's name
    mDBName = nameDB;
    // Use the database locally, without storing it
    auto dbImages = QSqlDatabase::addDatabase("QSQLITE", nameDB);
    bool ok = dbImages.open();
    if(!ok) {
        mError = dbImages.lastError().text();
        qDebug() << mError;
    }
    return ok;
}

QSqlDatabase dataInfo::getDatabase()
{
    return QSqlDatabase::database(mDBName);
}

dataInfo.h

private:
    QString mError;
    QString mDBName;

生成警告的 Qt 代码

查看产生错误的实际代码:https://code.woboq.org/qt5/qtbase/src/sql/kernel/qsqldatabase.cpp.html#170

invalidateDb用于添加或删除连接时,如果引用计数> 1 将触发错误。当您持有一个时,将触发错误。