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.xdnf.cn/news/1552016.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Chainlit集成LlamaIndex并使用通义千问实现和数据库交互的网页对话应用(text2sql)

前言 我在之前的几篇文章中写了如何使用Chainlit集成Langchain并使用通义千问实现和数据库交互的网页对话应用&#xff0c;但是发现Langchain的几种和数据库交互的组件都不够让我满意&#xff0c;虽然已经满足了大部分场景的需求&#xff0c;但是问题还是很多&#xff0c;比如…

无人机协同作业中的多网融合技术详解

无人机协同作业中的多网融合技术是一种复杂且高效的技术体系&#xff0c;它旨在通过整合多种通信网络和技术&#xff0c;实现多架无人机之间的无缝协同作业&#xff0c;从而提升任务执行效率、增强系统可靠性和扩展应用场景。以下是对该技术的详细解析&#xff1a; 一、多网融…

【C++】多态练习题(面试常考)

学习之前&#xff0c;建议观看&#xff1a;【C】多态&#xff1a;深度剖析&#xff08;多态、虚函数、抽象类、底层原理&#xff09;_c 多态和虚函数,虚函数的实现原理-CSDN博客https://blog.csdn.net/2301_80555259/article/details/142178677?spm1001.2014.3001.5501 一.概念…

解决 Macos下 Orbstack docker网络问题

两种解决方法&#xff0c;第一种开代理 参考 —— 但是我这一种没成功&#xff0c;第二种方法是换镜像源 { "registry-mirrors": ["http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn","https://mirrors.tencent.com&q…

《向量数据库指南》——Milvus 和 Fivetran 如何为 AI 构建基础

哈哈,说起 Milvus 和 Fivetran 如何为 AI 构建基础,这可真是个有意思的话题!来,让我这个向量数据库领域的“老司机”给你详细讲解一番,保证让你听得津津有味,还能学到不少干货! Milvus 和 Fivetran:AI 搜索解决方案的黄金搭档 在当今这个数据爆炸的时代,AI 已经成为…

使用MTVerseXR SDK实现VR串流

1、概述​ MTVerseXR SDK 是摩尔线程GPU加速的虚拟现实&#xff08;VR&#xff09;流媒体平台&#xff0c;专门用于从远程服务器流式传输基于标准OpenXR的应用程序。MTVerseXR可以通过Wi-Fi和USB流式将VR内容从Windows服务器流式传输到XR客户端设备, 使相对性能低的VR客户端可…

【10000字pandas数据可视化超全笔记整理】Numpy Pandas | 常用API介绍 | 缺失值处理 matplotlib数据可视化介绍

文章目录 Numpy 部分NumPy的数组类被称作ndarray&#xff0c;通常被称作数组。属性创建方法内置函数运算基本运算矩阵运算 Pandas部分总述Serise 对象创建属性方法运算 DataFrame属性索引操作添加删除插入列 保存读取文件保存读取 数据加载分组聚合语法格式: 基本绘图 数据组合…

Vue3 Typescript 前端页面5min后无操作自动退出至登录页面

效果图&#xff1a; 前端页面5min无操作&#xff0c;弹出弹窗提示用户系统将在30s后退出&#xff0c;30s后系统自动退出至登录页面。 <template><div><div class"f-z-20-px">{{ remainTime }}秒后无操作将退出</div><el-dialogtitle&quo…

C语言 getchar 函数完全解析:掌握字符输入的关键

前言 在C语言中&#xff0c;getchar 是一个非常实用的函数&#xff0c;用于从标准输入流&#xff08;通常是键盘&#xff09;读取单个字符。这对于处理文本输入非常有用&#xff0c;尤其是在需要逐个字符处理的情况下。本文将深入探讨 getchar 函数的用法和特点&#xff0c;并…

【Ubuntu】git

文章目录 1.配置SSH key2. 基础知识操作命令1分支branch 如果对git命令使用不熟悉&#xff0c;推荐一个非常棒的git在线练习工具 Learn Git Branching。 https://m.runoob.com/git/git-basic-operations.html 1.配置SSH key ssh-keygen -t rsa -C "YOUR EMAIL"完成…

软考中级网络规划设计师已过,分享一些备考心得

据说通过率只有15%左右&#xff0c;蛮低&#xff0c;但我还是一次过了。 其实参加考试的人不多&#xff0c;考场上来的人也就一半&#xff0c;很多人报名之后弃考了。。。所以我觉得最重要的还是坚持。 网规不像高项是热门科目&#xff0c;参考资料很多&#xff0c;自学的话某…

SpringBoot3响应式编程全套-Reactor核心

目录 传送门前言一、前置知识1、Lambda2、Function3、StreamAPI4、Reactive-Stream 二、Reactor1、快速上手1.1、介绍1.2、依赖 2、响应式编程2.1、阻塞是对资源的浪费2.2、异步可以解决问题吗&#xff1f;2.3、从命令式编程到响应式编程 三、核心特性1、Mono和Flux2、subscrib…

在 AI 大模型时代,了解 Agentic RAG 的核心理念至关重要

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ Agentic RAG&#xff0c;即基于智能体的检索增强生成技术&#xff0c;融合了 AI Agent 与 RAG 技术的优势。该技术通过集成 AI Agent&#xff0c;显著提升了 RAG 系统的智能水平与自主能力&#xff0c;…

1.7 编码与调制

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言前言1 基本术语2 常用的编码方法2.1 不归零编码2.2 归零编码2.3 反向归零编码2.4 曼彻斯特编码2.5 差分曼彻斯特编码 3 常用的调制方法3.1 调幅&#xff08;AM&#xff09…

Linux网络操作命令与函数全面总结

1. 引言 Linux作为服务器和开发平台&#xff0c;网络操作是其核心功能之一。本文旨在全面总结Linux系统中的网络操作方法&#xff0c;包括命令行工具和编程接口&#xff0c;帮助读者深入理解Linux网络管理的机制。 2. 命令行工具 2.1 ping 命令 ping 命令用于测试网络连接和…

【初阶数据结构】详解插入排序 希尔排序(内含排序的概念和意义)

文章目录 前言1. 排序的概念及其应用1.1 排序的概念1.2 排序的应用 2. 插入排序2.1 基本思想2.2 插入排序的代码实现2.3 插入排序算法总结 3. 希尔排序3.1 基本思想3.2 希尔排序的代码实现3.3 希尔排序的特征总结 前言 初级数据结构系列已经进入到了排序的部分了。相信大家听到…

DolphinScheduler 资源中心无法上传大文件

服务&#xff1a;dolphinscheduler 版本&#xff1a;v3.16 问题描述&#xff1a;资源中心-文件管理中使用文件上传是出现中断或上传失败 排除思路&#xff1a; 测试小文件或其他类型文件时是否正常&#xff1b;F12查看接口调用成功以及失败时的对比&#xff0c;发现接口调用…

内核级理解套接字和全连接队列

一、全连接队列 listen 函数第二个参数 backlog 是输入全连接队列的长度&#xff0c;一般不会太大。那如何理解全连接队列呢&#xff1f; 首先三次握手建立连接的过程和服务器是否 accept 无关&#xff0c;accept 的本质就是把已经建立的连接以文件描述符的形式返回。 那么在…

[含文档+PPT+源码等]精品大数据项目-基于Django实现的高校图书馆智能推送系统的设计与实现

大数据项目——基于Django实现的高校图书馆智能推送系统的设计与实现背景&#xff0c;可以从以下几个方面进行详细阐述&#xff1a; 一、信息技术的发展背景 随着信息技术的飞速发展和互联网的广泛普及&#xff0c;大数据已经成为现代社会的重要资源。在大数据背景下&#xf…

言语理解(3)

如果选项中填写的第一句话是文言文&#xff0c;那么尤其要注意它后面的第一句话 D B 要注意要填写的句子后面最近的一句话 文艺和时代和文章中的主题词&#xff0c;B和D的区别就是文艺带动时代向前发展&#xff0c;D是文艺和时代互相影响&#xff0c;从全文可知是文艺影响时代带…