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知识付费软件,为知识创业者或商家提供一站式内容交付解决方案,助力商家搭建集品牌传播、商业变现和用户运营于一体的线上知识服务系统,覆盖全渠道经营场景,占据每个流量入口,使流量变现快速高效…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
