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 将触发错误。当您持有一个时,将触发错误。
抱歉,如果这是一个微不足道的问题,但我一直在尝试创建一个小的 .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
代码片段下方:
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 将触发错误。当您持有一个时,将触发错误。