将项目从
Qt5.10.1
迁移到
Qt5.12.4
,发现封装的数据库相关代码报错,主要是以下两种:
-
QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
-
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);
如果在doSqlFunA和doSqlFunB中调用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官方解决方法另外一种解决方式碎碎念关于智能指针
今天在做之前代码的重构的时候,在调用QSqlDatabase的removeDatabase函数的时候,出现了如下错误
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: connection ‘qt_sql_default_connection’ is still in use, all queries will cease to work.QSqlDatabasePrivate::addDatabase: duplicate connecti