将项目从 Qt5.10.1 迁移到 Qt5.12.4 ,发现封装的数据库相关代码报错,主要是以下两种:

  1. QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
  2. QSqlDatabasePrivate::removeDatabase: connection ‘xxx’ is still in use, all queries will cease to work.

Qt5.10.1 Qt5.12.4 的官方帮助文档中搜索 Thread-Support in Qt Modules ,都可以看到如下说明,但是同样的代码在 Qt5.10.1 中却没有报错,连警告都没有。

Threads and the SQL Module
A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.
In addition, the third party libraries used by the QSqlDrivers can impose further restrictions on using the SQL Module in a multithreaded program. Consult the manual of your database client for more information.

现在开始分别分析在 Qt5.12.4 中出现上述问题的原因和解决方法。
问题一:

QSqlDatabasePrivate::database: requested database does not belong to the calling thread.

出现此问题,是由于在 线程A 中创建了数据库中的连接,在 线程B 中使用此数据库连接去执行增、删、、改查等操作。所以,避免此问题,只要在操作数据库查询的线程中创建连接即可。

QSqlDatabasePrivate::removeDatabase: connection ‘xxx’ is still in use, all queries will cease to work.

Qt5.12.4 帮助文档中关于removeDatabase的使用方法如下,强调了在调用removeDatabase前,需要把QSqlDatabase和QSqlQuery销毁。否则,就会出现上述警告。

[static] void QSqlDatabase::removeDatabase(const QString &connectionName)
Removes the database connection connectionName from the list of database connections.
Warning: There should be no open queries on the database connection when this function is called, otherwise a resource leak will occur.
Example:
// WRONG
QSqlDatabase db = QSqlDatabase::database(“sales”);
QSqlQuery query(“SELECT NAME, DOB FROM EMPLOYEES”, db);
QSqlDatabase::removeDatabase(“sales”); // will output a warning
// “db” is now a dangling invalid database connection,
// “query” contains an invalid result set
The correct way to do it:
{
QSqlDatabase db = QSqlDatabase::database(“sales”);
QSqlQuery query(“SELECT NAME, DOB FROM EMPLOYEES”, db);
}
// Both “db” and “query” are destroyed because they are out of scope
QSqlDatabase::removeDatabase(“sales”); // correct
To remove the default connection, which may have been created with a call to addDatabase() not specifying a connection name, you can retrieve the default connection name by calling connectionName() on the database returned by database(). Note that if a default database hasn’t been created an invalid database will be returned.

根据文档的提示,可以修改下代码,简单封装下。

QSqlDatabase DBUtil::openDataBase(QString connectionnName)
    QSqlDatabase db;
    if ( true == QSqlDatabase::contains(connectionnName)
        db = QSqlDatabase::database(connectionnName);
        db = QSqlDatabase::addDatabase("QSQLITE", connectionnName);
        db.setDatabaseName("xxx.db");
    if (false == db.open())
        qDebug() << db.lastError().text();
    return db;
void DBUtil::closeDataBase(QString connectionName)
    QSqlDatabase::removeDatabase(connectionName);
void DBUtil::executeSql()
    QString connectionName;
        QSqlDatabase db = DBUtil::openDataBase(”your db connect name“);
        connectionName = db.connectionName();
        QSqlQuery query(db);
        query.prepare(sql);
        /* do your sql */
    DBUtil::closeDataBase(connectionName);

拓展问题
如果你的代码中不使用QtConcurrent,那上述代码应该也够用了。不巧的时,由于有大量数据需要并行处理,所以我的代码中使用了QtConcurrent::run,如下。

void procData()
	QFuture<void> groupFuture = QtConcurrent::run(doSqlFunA);
	QFuture<void> cameraFuture = QtConcurrent::run(doSqlFunB);

如果在doSqlFunAdoSqlFunB中调用DBUtil::openDataBase使用了相同的数据库连接名称,那就会出现问题一的错误了。原因是doSqlFunA在调用DBUtil::openDataBase时,创建了数据库连接A;紧接着,doSqlFunB在调用DBUtil::openDataBase时,由于数据库连接A已经创建,且没有被销毁,所以doSqlFunB直接使用了数据库连接A,而没有新建,导致使用了其他线程创建的数据库连接而报错。
当然,你可以在每次调用DBUtil::openDataBase时,传入不同的名称,避免这个问题。更高效的方法是改进下DBUtil::openDataBase封装,用随机数作为数据库的连接名称。

QSqlDatabase DBUtil::openDataBase()
    quint32 value = QRandomGenerator::global()->generate();
    QSqlDatabase db;
    if ( true == QSqlDatabase::contains(QString::number(value)))
        db = QSqlDatabase::database(QString::number(value));
        db = QSqlDatabase::addDatabase("QSQLITE", QString::number(value));
        db.setDatabaseName("xxx.db");
    if (false == db.open())
        qDebug() << db.lastError().text();
    return db;
    * 获取连接时不需要了解连接的名字,连接池内部维护连接的名字
    * 支持多线程,保证获取到的连接一定是没有被其他线程正在使用
    * 按需创建连接,可以创建多个连接,可以控制连接的数量
    * 连接被复用,不是每次都重新创建一个新的连接(连接的创建是一个很消耗资源的过程)
    * 连接断开了后会自动重连
    * 当无可用连接时,获取连接的线程会等待一定时间尝试继续获取,直到取到有效连接或者超时返回一个无效的连接
    * 关闭连接很简单
                                    Qt Creator  多线程读取文件到程序显示
                 利用QT Creator多任务读取一个文档到程序里
   为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。
   效果图如下:
其中pro文件无需改动,默认就好,头文件h里面的内容为
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include 
#include 
#include 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MyObj;
class MyObj : public QObject
    Q_OBJECT
public:
    MyObj(); //新的线程
signals:
    void toLine(QString line);
private slots:
    void doWork();
class MainWindow : public QMainWindow
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void appendText(QString); //定义一个槽
private:
    Ui::MainWindow *ui;
    QThread *t;
    MyObj *obj;
#endif // MAINWINDOW_H
而MAIN主文件的内容为了防止中文乱码做了如下修改:
#include "mainwindow.h"
#include 
#include 
int main(int argc, char *argv[])
    QApplication a(argc, argv);
    //设置中文字体 防止乱码
    a.setFont(QFont("Microsoft Yahei", 9));
    //设置中文编码
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
    QTextCodec *codec = QTextCodec::codecForName("GBK");
#else
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForTr(codec);
#else
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
    QTextCodec::setCodecForLocale(codec);
#endif
    MainWindow w;
    w.show();
    return a.exec();
接下来重点来了,源文件CPP里为
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 
#include 
#include 
#include 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    ui->setupUi(this);
    t = new QThread();      //QThread
    obj = new MyObj();
    obj->moveToThread(t);
    qDebug()<<"main thread:"<<QThread::currentThread();
    connect(t,SIGNAL(started()), obj, SLOT(doWork()));
    connect(obj,SIGNAL
                                    在需要使用多线程读写数据库的场景中,可以考虑使用Qt的信号槽机制,将数据库操作放到独立的线程中执行。具体地,在子线程中创建新的数据库连接并操作数据库(同样可以使用。等类),将查询结果或操作结果通过信号/槽机制传递回主线程并更新UI界面。// 将主窗口与DBThread线程的信号/槽连接起来。// 启动一个新的线程执行数据库操作。// 在子线程中打开数据库连接。// 在子线程中执行数据库操作。// 在子线程中关闭数据库连接。// 在主线程中更新UI界面。// 新建一个线程类,用于执行数据库操作Qt在使用数据库时(本例以Sqlite为例),如创建数据库连接和使用数据库连接不在一个线程中,会出现如下报错:
QSqlDatabasePrivate::database: requested database does not belong to the calling thread
创建数据库连接程序
//m_sqlDataBase全局变量
m_sqlDataBase = QSqlDatabase::addDatabase("QSQLITE");
m_sqlD
void MainWindow::connectMYSQL(QString linkName)
    if (QSqlDatabase::contains(linkName))//判断testConnect连接是否存在并连接
        databa.
                                    文章目录问题描述Qt官方解决方法另外一种解决方式碎碎念关于智能指针
今天在做之前代码的重构的时候,在调用QSqlDatabaseremoveDatabase函数的时候,出现了如下错误
QSqlDatabasePrivate::removeDatabase: connection '1638178058438' is still in use, all queries will cease to work
Qt官方解决方法
在Qt的官方文档中,有对removeDatabase这个函数的注释。
                                    QSqlDatabasePrivate::removeDatabase: connection 'XXX' is still in use, all queries will cease to work.
很多QT新手多线程使用数据库时,经常遇到警告:
QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
究其原因,帮助助手明确说明
Threads and the SQL Module
A connection can only be used from within the thread that created it. Moving connections bet
                                    1. 解决QSqlDatabasePrivate::removeDatabase: connection ‘myConnection’ is still in use, all queries will cease to work的问题
该问题主要是因为没有关闭之前的数据库连接,然后又需要创建新的数据库连接导致。解决方案:必须释放该连接的所有查询,即删除所有与该连接有关的query;同时在释放该连...
这样运行会出现警告:QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
                                    Oracle Database 11g中增加了一个重要的功能,可以在不使用现有的RMAN备份或手动拷贝文件的情况下复制数据库。如果您之前不使用RMAN备份,那么现在可以利用RMAN复制功能创建备用数据库、测试环境或开发环境,而不必事先创建RMAN备份。此功能利用网络,所以也被称为网络使能的数据库复制(Network-enabled Database Duplication)或活动数据库复制。
RM...
                                    环境:windows10 + MYSQL + Qt5.9.9
几个月前,参与开发的一个项目中需要多次连接同一个数据库进行操作,但是执行的时候发现报了以下错误:
QSqlDatabasePrivate::removeDatabase: connectionqt_sql_default_connection’ is still in use, all queries will cease to work.QSqlDatabasePrivate::addDatabase: duplicate connecti