Qt SQLite数据库多线程的使用方式3
Posted kupeThinkPoem
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt SQLite数据库多线程的使用方式3相关的知识,希望对你有一定的参考价值。
一、QSqlDatabase概述
QSqlDatabase提供了一系列的接口用于访问操作数据库,包括连接数据库,输入sql语句等。
QSqlDatabase的实例表示着一个对数据库的连接。该连接通过一个受支持的数据库驱动程序(从QSqlDriver派生)提供对数据库的访问。另外,可以从QSqlDriver子类化自己的数据库驱动程序。(如何创建自己的驱动,详见其他文档)Qt支持的数据库有很多,自己首先接触到的是QODBC(用于sql server)。另外还有QSQLITE、QDB2、QIBASE、Qmysql等。
二、QSqlDatabase模块的使用
QSqlDatabase类处理与数据库的连接,要使用这个类,头文件需要导入QSqlDatabase库:
#include <QSqlDatabase>
在qmake.pro文件中加入SQL数据库支持:
QT += sql
这个类提供了以下公共方法:QSqlDatabase::addDatabase、QSqlDatabase::removeDatabase和QSqlDatabase::database函数都是线程安全的。但是open不是线程安全的,所以在open时需要加上锁。
三、多线程操作不同的链接
在Qt中使用SQLite数据库多线程的方式,一般可以采用以下步骤:
-
在主线程中打开和创建数据库连接,并创建需要操作的表格。在这里可以使用
QSqlDatabase
和QSqlQuery
等类进行数据库连接和操作。 -
在需要使用多线程读写数据库的场景中,可以考虑使用Qt的信号槽机制,将数据库操作放到独立的线程中执行。具体地,在子线程中创建新的数据库连接并操作数据库(同样可以使用
QSqlDatabase
和QSqlQuery
等类),将查询结果或操作结果通过信号/槽机制传递回主线程并更新UI界面。
以下是一个示例代码,演示如何在多线程中使用SQLite数据库:
// 新建一个线程类,用于执行数据库操作
class DBThread : public QThread
Q_OBJECT
public:
explicit DBThread(QObject *parent = 0) : QThread(parent)
signals:
void resultReady(const QString &result);
protected:
void run() override
// 在子线程中打开数据库连接
QSqlDatabase *pdb=NULL;
QMutexLocker locker(&g_mutex);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","唯一的连接名,需要自己设置");
db.setDatabaseName("myDB.db");
pdb=&db;
if (!db.open())
emit resultReady("Error: failed to connect database.");
return;
// 在子线程中执行数据库操作
QSqlQuery query(*pdb);
if (query.exec("SELECT * FROM myTable"))
QString result;
while (query.next())
QString name = query.value(0).toString();
int age = query.value(1).toInt();
result += QString("Name: %1, Age: %2\\n").arg(name).arg(age);
emit resultReady(result);
else
emit resultReady("Error: failed to execute query.");
// 在子线程中关闭数据库连接
db.close();
;
// 主窗口类,用于与UI界面交互和更新结果
class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) : QMainWindow(parent)
// 创建操作按钮并绑定槽函数
QPushButton *queryButton = new QPushButton(tr("Query"), this);
connect(queryButton, &QPushButton::released, this, &MainWindow::handleQuery);
// 创建文本框并添加到主窗口
outputWidget = new QTextEdit(this);
outputWidget->setReadOnly(true);
setCentralWidget(outputWidget);
statusBar();
// 将主窗口与DBThread线程的信号/槽连接起来
thread = new DBThread(this);
connect(thread, &DBThread::finished, thread, &QObject::deleteLater);
connect(thread, &DBThread::resultReady, this, &MainWindow::showResult);
private slots:
void handleQuery()
// 启动一个新的线程执行数据库操作
thread->start();
void showResult(const QString &result)
// 在主线程中更新UI界面
outputWidget->setPlainText(result);
private:
DBThread *thread;
QTextEdit *outputWidget;
;
在上述示例代码中,我们创建了一个 DBThread
类用于在子线程中执行数据库操作,该类继承自 QThread
类。在主窗口类的成员函数 handleQuery()
中,我们启动了一个新的 DBThread
线程,并在主窗口类的成员函数 showResult()
中更新UI界面。
当在子线程中执行完毕后,通过 emit
语句发射信号通知主线程界面需要更新,这里使用了 resultReady()
信号。主窗口类将这个信号与自己的槽函数 showResult()
绑定起来,以接收子线程发送的结果并更新UI界面。
qt对sqlite数据库多线程的操作
对数据库多线程的操作:
一开始写的程序由于没有注意到多线程对数据库和对整个程序的影响,虽然程序没有报错,但是在后期的长时间调试的时候暴露出了很多问题。
首先是程序运行两个小时后会出现数据库死锁无法操作的问题,前期通过给数据库操作进行加锁仍无法解决该问题。后经过查找资料,经过解决了该问题。所以在此总结一下多线程数据操作时应该进行的处理:
这是一段标准的多线程前提下对数据库进行的操作(我自认为的哈),将会按照这段代码进行说明。
1多线程下的各个线程或是定时器数据库驱动加载需要独立进行
之前写程序,当一个程序多个类需要操作同一个数据库时,处理结果是将数据库的QsqlDatabase作为参数传给需要的子类。这样做在单进程的程序里没有太大的问题。但是在多线程里,由于线程的特殊性,这样做就会出现问题。所以最好的办法就是,在每个线程或是定时器里,单独的进行数据库驱动的加载,定义一个不同的名字。并且在使用中,QsqlQuery变量一定要设置当前所在现成的QsqlDatabase作为参数:
2 多线程操作数据库一定要加锁
这点一般都会做,需要注意一点的就是如果程序里如果有加数据库打开判断的话,一定要记得打开失败return的时候给解锁,不然也会非常容易的造成死锁。
3 数据库最好是每次操作的时候再打开,用完就关闭,不要一直打开不关
数据库打开的时候会有一个临时文件,将数据都转移到临时文件进行操作,如果不关闭的话,这个临时文件是不会清除的,也就是说你的另一个线程正好要操作数据库,那么数据库里面是没有数据的,所以,一定要每次操作的时候打开关闭。
4 重点说一下QsqlQuery 这个变量的问题
前期写代码测试的时候发现,在通过如上办法后,多线程下数据库仍然是经过俩小时必然思索,纠结了很久后开始换个思路打印一下调试信息,找了个数据库操作最频繁的代码段进行调试,估摸着打印了一下关闭数据库的时候的调试信息,发现虽然参数结果是-1,也就是正常关闭的参数,但是真正正常关闭数据库的错误信息后两个参数是空的,而我的打印出来后两个参数是数据库错误关闭的说明。这就很让人费解,能出错的也就只有QsqlQuery了,可是我再加上clear()和设置不同的变量名来测试发现,打印信息还是不正常,终于在咨询高人后得到的办法就是在每次声明QsqlQuery变量的时候,都加上一对花括号来设定这个变量的作用域生命周期,执行完这段代码就让它自己结束生命,果然,这次打印信息正常了。但是这个变量对内存的影响至今也不了解,为什么会产生这样的问题。以后水平提高可能会有所顿悟,但是现在只要能解决问题就好。
其他的数据库操作什么的不多说了。这次解决问题,学到的东西不少,要更加理解了一个道理,没有错误的代码不一定是优秀的代码。另外这次能比较快的定位出问题所在是关键,调试的过程就是不断的写打印信息,光靠猜是不行的。
这就是我对多线程下数据库遇到的一些问题进行总结,不足之处以后会补充
本人水平也有限,刚毕业的菜鸟,只是希望能对同样遇到问题的朋友有所帮助。哈哈
以上是关于Qt SQLite数据库多线程的使用方式3的主要内容,如果未能解决你的问题,请参考以下文章