QSqlDatabase:如何避免仍在使用'qt_sql_default_connection'和与重复连接有关的警告?

时间:2019-03-16 18:09:40

标签: c++ qt sqlite qt5 qtableview

很抱歉,如果这是一个小问题,但是我一直在尝试构建一个小的.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,此other sourcethis也很有用,但仍然没有任何反应。官方文档提出了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,该建议建议先为数据库设置名称,但是我已经在功能initDataBase(const QString &nameDB)中做到了。这是建议该操作的post,如下所示:

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

请阐明可能的解决方案。

1 个答案:

答案 0 :(得分:2)

简短答案

  • 您应指定要在其上运行QSqlQuery的数据库,否则它们将在默认数据库上运行。您可以使用{p>在QSqlQuery的构造函数中指定数据库

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

  • 您正在作为QSqlDatabase类的成员保留dataInfo的副本,这将防止它阻止正常关闭。相反,仅在需要时使用静态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属性

从文档中:

  

警告:强烈建议您不要保留QSqlDatabase的副本作为类的成员,因为这将导致实例在关闭时无法正确清理。如果需要访问现有的QSqlDatabase,则应使用database()访问它。如果选择使用QSqlDatabase成员变量,则需要在删除QCoreApplication实例之前将其删除,否则可能导致未定义的行为。

将您的数据库名称存储在您的班级中,然后将您的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,将触发错误。当您按住一个时,将触发错误。