当前位置: 首页 > news >正文

QSqlDatabase在多线程中的使用

Qt中多线程使用数据库_qt数据库管理类支持多数据库,多线程-CSDN博客

1.

代码:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDriver>
#include <QThread>
#include <QTextBrowser>
#include <QVBoxLayout>class Test : public QObject
{Q_OBJECT
public:Test(QSqlDatabase database):   QObject(nullptr), m_database(database){}
signals:void query_result(const QString &result);
public slots:void test_query(){m_database.open();QString str = "Thread ID: " + QString::number((int)QThread::currentThreadId(), 16) + "  result:";QSqlQuery query(m_database);query.exec("SELECT * FROM test;");while(query.next())str += query.value(0).toString() + "|";m_database.close();emit query_result(str + "\n");}
private:QSqlDatabase m_database;
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr):   QWidget(parent){QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "mydb");db.setPort(3306);db.setDatabaseName("test");db.setUserName("root");db.setPassword("root_pwd");test1 = new Test(db);test2 = new Test(db);test1->moveToThread(&thread1);test2->moveToThread(&thread2);thread1.start();thread2.start();QPushButton *button = new QPushButton("开始", this);QTextBrowser *browser = new QTextBrowser(this);browser->insertPlainText("UI Thread ID: " + QString::number((int)QThread::currentThreadId(), 16));QVBoxLayout *layout = new QVBoxLayout(this);layout->addWidget(button);layout->addWidget(browser);setLayout(layout);connect(button, &QPushButton::clicked, this, &Widget::start);connect(button, &QPushButton::clicked, this, [=](){browser->insertPlainText("\n");});connect(&thread1, &QThread::finished, &thread1, &QThread::deleteLater);connect(&thread2, &QThread::finished, &thread2, &QThread::deleteLater);connect(test1, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});connect(test2, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});resize(500, 400);}~Widget(){thread1.wait();thread2.wait();}public slots:void start(){QMetaObject::invokeMethod(test1, "test_query");QMetaObject::invokeMethod(test2, "test_query");}private:QThread thread1;QThread thread2;Test *test1;Test *test2;
};#endif // WIDGET_H

数据库: 

1000条记录:内容均为123

ui: 

 

有一个线程中的数据库没有打开

 ------

2.

修改代码:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDriver>
#include <QThread>
#include <QTextBrowser>
#include <QVBoxLayout>
#include <QDebug>
class Test : public QObject
{Q_OBJECT
public:Test(QSqlDatabase database):   QObject(nullptr), m_database(database){}
signals:void query_result(const QString &result);
public slots:void test_query(){qDebug()<<__FILE__<<"["<<__LINE__<<"]"<<m_database;m_database.open();qDebug()<<__FILE__<<"["<<__LINE__<<"]"<<m_database;QString str = "Thread ID: " + QString::number((int)QThread::currentThreadId(), 16) + "  result:";QSqlQuery query(m_database);query.exec("SELECT * FROM test;");while(query.next())str += query.value(0).toString() + "|";m_database.close();emit query_result(str + "\n");}
private:QSqlDatabase m_database;
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr):   QWidget(parent){QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "mydb000");db.setPort(3306);db.setDatabaseName("test");db.setUserName("root");db.setPassword("root_pwd");QSqlDatabase db1 = QSqlDatabase::addDatabase("QMYSQL", "mydb111");db1.setPort(3306);db1.setDatabaseName("test");db1.setUserName("root");db1.setPassword("root_pwd");test1 = new Test(db);test2 = new Test(db1);test1->moveToThread(&thread1);test2->moveToThread(&thread2);thread1.start();thread2.start();QPushButton *button = new QPushButton("开始", this);QTextBrowser *browser = new QTextBrowser(this);browser->insertPlainText("UI Thread ID: " + QString::number((int)QThread::currentThreadId(), 16));QVBoxLayout *layout = new QVBoxLayout(this);layout->addWidget(button);layout->addWidget(browser);setLayout(layout);connect(button, &QPushButton::clicked, this, &Widget::start);connect(button, &QPushButton::clicked, this, [=](){browser->insertPlainText("\n");});connect(&thread1, &QThread::finished, &thread1, &QThread::deleteLater);connect(&thread2, &QThread::finished, &thread2, &QThread::deleteLater);connect(test1, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});connect(test2, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});resize(500, 400);}~Widget(){thread1.wait();thread2.wait();}public slots:void start(){QMetaObject::invokeMethod(test1, "test_query");QMetaObject::invokeMethod(test2, "test_query");}private:QThread thread1;QThread thread2;Test *test1;Test *test2;
};#endif // WIDGET_H

不同的线程中使用不同的连接名:

发现还是不可以成功访问。

debug\../../demo/widget.h [ 27 ] QSqlDatabase(driver="QMYSQL", database="test", host="", port=3306, user="root", open=false)

debug\../../demo/widget.h [ 27 ] QSqlDatabase(driver="QMYSQL", database="test", host="", port=3306, user="root", open=false)

debug\../../demo/widget.h [ 29 ] QSqlDatabase(driver="QMYSQL", database="test", host="", port=3306, user="root", open=false)

QSqlQuery::exec: database not open

debug\../../demo/widget.h [ 29 ] QSqlDatabase(driver="QMYSQL", database="test", host="", port=3306, user="root", open=true)

只有一个数据库可以打开。。。

3.

Qt多线程操作MySql数据库 - 补码 - 博客园 (cnblogs.com)

看了看这篇文章,在

QSqlDatabase::addDatabase和QSqlDatabase::open外部加锁,然后两个数据库都可以打开了。

(应该是在执行这两个函数时,会有数据竞争的情况发生)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlDriver>
#include <QThread>
#include <QTextBrowser>
#include <QVBoxLayout>
#include <QDebug>
#include <QMutex>extern QMutex mutex;
class Test : public QObject
{Q_OBJECT
public:Test(const QString &connectName):   QObject(nullptr){mutex.lock();m_database = QSqlDatabase::addDatabase("QMYSQL",connectName);m_database.setHostName("127.0.0.1");m_database.setPort(3306);m_database.setDatabaseName("test");m_database.setUserName("root");m_database.setPassword("root_pwd");mutex.unlock();}
signals:void query_result(const QString &result);
public slots:void test_query(){qDebug()<<__FILE__<<"["<<__LINE__<<"]"<<m_database;mutex.lock();if(m_database.open()){qDebug()<<__FILE__<<"["<<__LINE__<<"]"<<m_database;QString str = "Thread ID: " + QString::number((int)QThread::currentThreadId(), 16) + "  result:";QSqlQuery query(m_database);query.exec("SELECT * FROM test;");while(query.next())str += query.value(0).toString() + "|";m_database.close();emit query_result(str + "\n");}else{qDebug()<<__FILE__<<"["<<__LINE__<<"]"<<m_database.lastError();}mutex.unlock();}
private:QSqlDatabase m_database;
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr):   QWidget(parent){test1 = new Test("db");test2 = new Test("db1");test1->moveToThread(&thread1);test2->moveToThread(&thread2);thread1.start();thread2.start();QPushButton *button = new QPushButton("开始", this);QTextBrowser *browser = new QTextBrowser(this);browser->insertPlainText("UI Thread ID: " + QString::number((int)QThread::currentThreadId(), 16));QVBoxLayout *layout = new QVBoxLayout(this);layout->addWidget(button);layout->addWidget(browser);setLayout(layout);connect(button, &QPushButton::clicked, this, &Widget::start);connect(button, &QPushButton::clicked, this, [=](){browser->insertPlainText("\n");});connect(&thread1, &QThread::finished, &thread1, &QThread::deleteLater);connect(&thread2, &QThread::finished, &thread2, &QThread::deleteLater);connect(test1, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});connect(test2, &Test::query_result, this, [=](const QString &result){browser->insertPlainText(result);});resize(500, 400);}~Widget(){thread1.wait();thread2.wait();}public slots:void start(){QMetaObject::invokeMethod(test1, "test_query");QMetaObject::invokeMethod(test2, "test_query");}private:QThread thread1;QThread thread2;Test *test1;Test *test2;
};#endif // WIDGET_H
#include <QApplication>
#include "widget.h"QMutex mutex;
int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

debug\../../demo/widget.h [ 38 ] QSqlDatabase(driver="QMYSQL", database="test", host="127.0.0.1", port=3306, user="root", open=false)

debug\../../demo/widget.h [ 38 ] QSqlDatabase(driver="QMYSQL", database="test", host="127.0.0.1", port=3306, user="root", open=false)

debug\../../demo/widget.h [ 42 ] QSqlDatabase(driver="QMYSQL", database="test", host="127.0.0.1", port=3306, user="root", open=true)

debug\../../demo/widget.h [ 42 ] QSqlDatabase(driver="QMYSQL", database="test", host="127.0.0.1", port=3306, user="root", open=true)

 ---

在使用多线程时,特别需要注意的就是刚才出现的情况。

如:有两个线程,它们同时要访问一个共有的资源,这时候就会出现对资源的竞争,如果不添加锁,会出现什么情况将是未知的。

比如上面的例子:

m_database.open()

线程1打开数据库成功,它的流程正常进行。

而线程2打开数据库失败,此时让流程继续走下去,结果不是我们期望的,所以要加锁。 

http://www.lryc.cn/news/450551.html

相关文章:

  • 【无人机设计与控制】Multi-UAV|多无人机多场景路径规划算法MATLAB
  • Visual Studio C# 编写加密火星坐标转换
  • 微服务-流量染色
  • C语言实现 操作系统 经典的进程同步问题(2)
  • 有效的字母异位词【字符串哈希】
  • 如何选择与运用工具提升工作效率的秘密指南
  • Spring系列 AOP实现过程
  • C语言 getchar 函数完全解析:掌握字符输入的关键
  • Docker安装mysql8并配置主从复制
  • 快手:数据库升级实践,实现PB级数据的高效管理|OceanBase案例
  • 基于Node.js+Express+MySQL+VUE实现的计算机毕业设计共享单车管理网站
  • 人工智能辅助的神经康复
  • KKT实际运用 -MATLAB
  • php在线相册
  • Xcode手动安装SDK模拟器
  • Docker安装consul + go使用consul + consul知识
  • JWT 漏洞 - 学习手册
  • HTML【知识改变命运】03font 字体标签
  • 集师专属知识付费小程序搭建 心理咨询小程序搭建
  • https://www.aitoolpath.com/ 一个工具数据库,目前储存了有2000+各种工具。每日更新
  • 科技的成就(六十三)
  • 浅谈抗量子密码学:保护未来的数字安全
  • 10款物联网开源嵌入式操作系统对比分析
  • Elasticsearch深度攻略:核心概念与实践应用
  • TLS详解
  • 正则表达式中的特殊字符
  • EP42 公告详情页
  • 游戏找不到xinput1_3.dll的原因及解决方法
  • 防反接电路设计
  • SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器