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打开数据库失败,此时让流程继续走下去,结果不是我们期望的,所以要加锁。
相关文章:
QSqlDatabase在多线程中的使用
Qt中多线程使用数据库_qt数据库管理类支持多数据库,多线程-CSDN博客 1. 代码: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError>…...
【无人机设计与控制】Multi-UAV|多无人机多场景路径规划算法MATLAB
摘要 本研究探讨了多无人机路径规划问题,提出了三种不同算法的对比分析,包括粒子群优化(PSO)、灰狼优化(GWO)和鲸鱼优化算法(WOA)。利用MATLAB实现了多场景仿真实验,验证…...
Visual Studio C# 编写加密火星坐标转换
Visual Studio C# 编写加密火星坐标转换 1、WGS84坐标转GCJ02火星坐标2、GCJ02火星坐标转WGS84坐标(回归计算)3、GCJ02火星坐标转BD09百度坐标4、BD09百度坐标转GCJ02火星坐标(回归计算)5、坐标公共转换类6、地图显示7、程序简单界…...
微服务-流量染色
1. 功能目的 通过设置请求头的方式将http请求优先打到指定的服务上,为微服务开发调试工作提供便利 请求报文难模拟:可以直接在测试环境页面上操作,流量直接打到本地IDEA进行debug请求链路较长:本地开发无需启动所有服务…...
C语言实现 操作系统 经典的进程同步问题(2)
哲学家进餐问题 哲学家进餐问题是一个经典的同步问题,涉及多个哲学家试图同时用餐,但每个哲学家左右两边只有一把叉子。为了避免死锁和饥饿,可以使用记录型信号量(也称为计数信号量)来管理叉子的使用。 1、利用记录型…...
有效的字母异位词【字符串哈希】
题目 题解: 1.排序: #include<algorithm>class Solution{public:bool isAnagram(string s,string t){sort(s.begin(),s.end());sort(t.begin(),t.end());return st;} } 时间复杂度O(nlogn) 2.哈希表 #include<algorithm>int hash1[100]; …...
如何选择与运用工具提升工作效率的秘密指南
一、引言 ---- 在当今这个信息爆炸的时代,编程工具的选择对于开发者的工作效率至关重要。从智能的代码编辑器到强大的版本控制工具,再到那些能让我们事半功倍的自动化脚本,每一款工具都有其独特的优势和价值。那么,哪款编程工具…...
Spring系列 AOP实现过程
文章目录 实现原理EnableAspectJAutoProxyAnnotationAwareAspectJAutoProxyCreator 代理创建过程wrapIfNecessarygetAdvicesAndAdvisorsForBeanfindCandidateAdvisorsfindAdvisorsThatCanApply createProxy AspectJ注解处理代理调用过程 实现原理 本文源码基于spring-aop-5.3.…...
C语言 getchar 函数完全解析:掌握字符输入的关键
前言 在C语言中,getchar 是一个非常实用的函数,用于从标准输入流(通常是键盘)读取单个字符。这对于处理文本输入非常有用,尤其是在需要逐个字符处理的情况下。本文将深入探讨 getchar 函数的用法和特点,并…...
Docker安装mysql8并配置主从复制
1. 安装mysql8 1.1 新增挂载文件 # 新增mysql挂载文件夹 mkdir -p /root/docker/mysql/m01/log mkdir -p /root/docker/mysql/m01/data mkdir -p /root/docker/mysql/m01/conf1.2 新增mysql配置文件 # 新增mysql配置文件 cd /root/docker/mysql/m01/conf vim my.cnf # 下面是…...
快手:数据库升级实践,实现PB级数据的高效管理|OceanBase案例
本文作者:胡玉龙,快手技术专家 快手在较初期采用了OceanBase 3.1版本成功替换了多个核心业务、数百套的MySQL集群。至2023年,快手的数据量已突破800TB大关,其中最大集群的数据量更是达到了数百TB级别。为此,快手将数据…...
基于Node.js+Express+MySQL+VUE实现的计算机毕业设计共享单车管理网站
单车信息选择骑行 骑行状态留言公告/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序 目录 功能图 界面展示 开发目标 开发背景意义 开发意义 开发目的 项目概述 技术选型与理由 系统设计与功能实现 项目可执行性分析 系统架构需求 性能需…...
人工智能辅助的神经康复
人工智能辅助的神经康复是通过应用人工智能(AI)技术来改善神经系统损伤患者的康复过程。此领域结合了深度学习、数据分析和机器人技术,旨在提升康复效果、个性化治疗方案和监测进展。以下是该领域的关键组成部分和应用: 1. 康复评…...
KKT实际运用 -MATLAB
FMINCON函数可以很方便的求出:fun:目标函数,即需要最小化的函数,输入参数为向量x,输出为标量f(x)。x0:初始点,即求解过程的起始点,可以是标量、向量或矩阵。A和b:线性不等…...
php在线相册
1、将静态页面效果完成 解压到www里 整个数据 暂时是错误的 建立连接密码为root 运行sql文件 右键根目录刷新 刷新后成功 开始 测试 如果需要上传照片,点击创建相册,选择上传文件,选择文件后退出 导入alumbenew2 2.提交表单方式 3.利用ph…...
Xcode手动安装SDK模拟器
1.下载SDK模拟器&Xcode SDK和Xcode官方下载地址 2.下载好后使用命令将SDK导入到Xcode中如下命令 注:我是在/Applications 目录下执行的命令,模拟其地址直接拖拽过来 sudo xcode-select -s Xcode.app xcodebuild -runFirstLaunch xcodebuild -imp…...
Docker安装consul + go使用consul + consul知识
1. 什么是服务注册和发现 假如这个产品已经在线上运行,有一天运营想搞一场促销活动,那么我们相对应的【用户服务】可能就要新开启三个微服务实例来支撑这场促销活动。而与此同时,作为苦逼程序员的你就只有手动去 API gateway 中添加新增的这…...
JWT 漏洞 - 学习手册
0x01:JWT 前导知识 0x0101:JWT 详解 0x02:JWT 漏洞介绍 0x0201:JWT 漏洞介绍 0x03:JWT 挖掘思路 JWT 漏洞挖掘思路 - JWT Payload 敏感信息泄露 备注:通过泄露的 JWT Payload 获取用户的敏感信息&#…...
HTML【知识改变命运】03font 字体标签
题目:在页面上显示"北京"两个字,字体为微软雅黑,颜色为红色,大小为40xp; font标签可以修饰字体的大小,颜色,和字体 属性:color颜色,face字体,size大…...
集师专属知识付费小程序搭建 心理咨询小程序搭建
一、产品简介 集师SaaS知识付费软件,为知识创业者或商家提供一站式内容交付解决方案,助力商家搭建集品牌传播、商业变现和用户运营于一体的线上知识服务系统,覆盖全渠道经营场景,占据每个流量入口,使流量变现快速高效…...
KITTI 3D目标检测评估工具evaluate_object.cpp编译与使用避坑指南(附修改代码)
KITTI 3D目标检测评估工具深度解析:从编译优化到实战技巧 在自动驾驶算法研发领域,KITTI数据集及其评估工具链已成为行业事实上的黄金标准。作为计算机视觉与自动驾驶研究的重要基础设施,KITTI评估工具的正确使用直接关系到算法性能评估的准确…...
GCC开发者转LLVM必看:模块化设计带来的5个关键工作流变革
GCC开发者转LLVM必看:模块化设计带来的5个关键工作流变革 当GCC开发者第一次接触LLVM时,往往会惊讶于其完全不同的设计哲学。就像从单块巨石建筑转向预制模块化结构,LLVM的三段式架构不仅改变了代码的组织方式,更从根本上重塑了编…...
Harmonyos应用实例214:空间角与距离计算器
6. 空间角与距离计算器 功能简介:利用空间向量计算异面直线所成角、直线与平面所成角、二面角,以及点到平面的距离。通过输入向量坐标,实时计算并展示结果,帮助学生掌握空间角与距离的向量计算方法。 ArkTS代码: @Entry @Component struct SpaceVectorCalculator {@Stat…...
AI开发不再卡顿:RTX4090D 24G镜像解决环境冲突全攻略
AI开发不再卡顿:RTX4090D 24G镜像解决环境冲突全攻略 1. 为什么选择RTX4090D 24G深度学习镜像? 深度学习开发者最头疼的问题莫过于环境配置。不同框架版本、CUDA版本、依赖库之间的冲突常常让人望而却步。传统环境搭建方式需要: 手动安装C…...
零基础学编程:借助快马与claude code生成交互式代码示例入门javascript
最近刚开始学习JavaScript,发现数组操作是编程中最基础也最常用的部分。作为一个完全零基础的小白,我尝试用InsCode(快马)平台结合Claude Code来学习这个知识点,整个过程比想象中顺利很多。这里记录下我的学习过程,希望能帮到同样…...
Win11Debloat:3步解决Windows系统卡顿与隐私泄露难题
Win11Debloat:3步解决Windows系统卡顿与隐私泄露难题 【免费下载链接】Win11Debloat 一个简单的PowerShell脚本,用于从Windows中移除预装的无用软件,禁用遥测,从Windows搜索中移除Bing,以及执行各种其他更改以简化和改…...
爆款AI写教材工具登场!一键生成低查重教材,轻松开启编写之旅
编写教材的困境与AI的解决方案 在编写教材时,如何准确地满足多样化的需求呢?不同年级的学生在认知能力上存在显著差异,教材内容若过于深奥或过于简单都无法达到效果;而课堂教学和自主学习等不同的环境对教材的要求各不相同&#…...
ai辅助stm32开发,向快马描述需求即可获得精准的f103c8t6引脚配置代码
最近在做一个基于STM32F103C8T6的小项目,需要用到UART、I2C、PWM、ADC和GPIO等多种外设。作为嵌入式开发新手,最头疼的就是引脚分配和初始化代码的编写。好在发现了InsCode(快马)平台的AI辅助开发功能,用自然语言描述需求就能得到专业的代码解…...
DML实战:价格弹性预测的经济学与机器学习融合之道
1. 价格弹性预测:经济学与机器学习的碰撞 第一次听说价格弹性还能用机器学习预测时,我的反应和大多数经济学背景的同事一样:"这不就是个回归问题吗?"直到亲眼看到某电商平台用DML模型把促销预算节省了23%,才…...
Uvicorn与Couchbase Analytics Service集成:构建高性能数据分析API的终极指南
Uvicorn与Couchbase Analytics Service集成:构建高性能数据分析API的终极指南 【免费下载链接】uvicorn An ASGI web server, for Python. 🦄 项目地址: https://gitcode.com/GitHub_Trending/uv/uvicorn 在现代数据驱动的应用开发中,…...
