当前位置: 首页 > 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打开数据库失败,此时让流程继续走下去,结果不是我们期望的,所以要加锁。 

相关文章:

QSqlDatabase在多线程中的使用

Qt中多线程使用数据库_qt数据库管理类支持多数据库,多线程-CSDN博客 1. 代码&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError>…...

【无人机设计与控制】Multi-UAV|多无人机多场景路径规划算法MATLAB

摘要 本研究探讨了多无人机路径规划问题&#xff0c;提出了三种不同算法的对比分析&#xff0c;包括粒子群优化&#xff08;PSO&#xff09;、灰狼优化&#xff08;GWO&#xff09;和鲸鱼优化算法&#xff08;WOA&#xff09;。利用MATLAB实现了多场景仿真实验&#xff0c;验证…...

Visual Studio C# 编写加密火星坐标转换

Visual Studio C# 编写加密火星坐标转换 1、WGS84坐标转GCJ02火星坐标2、GCJ02火星坐标转WGS84坐标&#xff08;回归计算&#xff09;3、GCJ02火星坐标转BD09百度坐标4、BD09百度坐标转GCJ02火星坐标&#xff08;回归计算&#xff09;5、坐标公共转换类6、地图显示7、程序简单界…...

微服务-流量染色

1. 功能目的 通过设置请求头的方式将http请求优先打到指定的服务上&#xff0c;为微服务开发调试工作提供便利 请求报文难模拟&#xff1a;可以直接在测试环境页面上操作&#xff0c;流量直接打到本地IDEA进行debug请求链路较长&#xff1a;本地开发无需启动所有服务&#xf…...

C语言实现 操作系统 经典的进程同步问题(2)

哲学家进餐问题 哲学家进餐问题是一个经典的同步问题&#xff0c;涉及多个哲学家试图同时用餐&#xff0c;但每个哲学家左右两边只有一把叉子。为了避免死锁和饥饿&#xff0c;可以使用记录型信号量&#xff08;也称为计数信号量&#xff09;来管理叉子的使用。 1、利用记录型…...

有效的字母异位词【字符串哈希】

题目 题解&#xff1a; 1.排序&#xff1a; #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]; …...

如何选择与运用工具提升工作效率的秘密指南

一、引言 ----  在当今这个信息爆炸的时代&#xff0c;编程工具的选择对于开发者的工作效率至关重要。从智能的代码编辑器到强大的版本控制工具&#xff0c;再到那些能让我们事半功倍的自动化脚本&#xff0c;每一款工具都有其独特的优势和价值。那么&#xff0c;哪款编程工具…...

Spring系列 AOP实现过程

文章目录 实现原理EnableAspectJAutoProxyAnnotationAwareAspectJAutoProxyCreator 代理创建过程wrapIfNecessarygetAdvicesAndAdvisorsForBeanfindCandidateAdvisorsfindAdvisorsThatCanApply createProxy AspectJ注解处理代理调用过程 实现原理 本文源码基于spring-aop-5.3.…...

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

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

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案例

本文作者&#xff1a;胡玉龙&#xff0c;快手技术专家 快手在较初期采用了OceanBase 3.1版本成功替换了多个核心业务、数百套的MySQL集群。至2023年&#xff0c;快手的数据量已突破800TB大关&#xff0c;其中最大集群的数据量更是达到了数百TB级别。为此&#xff0c;快手将数据…...

基于Node.js+Express+MySQL+VUE实现的计算机毕业设计共享单车管理网站

单车信息选择骑行 骑行状态留言公告/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序 目录 功能图 界面展示 开发目标 开发背景意义 开发意义‌ 开发目的 项目概述‌ 技术选型与理由‌ 系统设计与功能实现‌ 项目可执行性分析 ‌系统架构需求‌ ‌性能需…...

人工智能辅助的神经康复

人工智能辅助的神经康复是通过应用人工智能&#xff08;AI&#xff09;技术来改善神经系统损伤患者的康复过程。此领域结合了深度学习、数据分析和机器人技术&#xff0c;旨在提升康复效果、个性化治疗方案和监测进展。以下是该领域的关键组成部分和应用&#xff1a; 1. 康复评…...

KKT实际运用 -MATLAB

FMINCON函数可以很方便的求出&#xff1a;fun&#xff1a;目标函数&#xff0c;即需要最小化的函数&#xff0c;输入参数为向量x&#xff0c;输出为标量f(x)。x0&#xff1a;初始点&#xff0c;即求解过程的起始点&#xff0c;可以是标量、向量或矩阵。A和b&#xff1a;线性不等…...

php在线相册

1、将静态页面效果完成 解压到www里 整个数据 暂时是错误的 建立连接密码为root 运行sql文件 右键根目录刷新 刷新后成功 开始 测试 如果需要上传照片&#xff0c;点击创建相册&#xff0c;选择上传文件&#xff0c;选择文件后退出 导入alumbenew2 2.提交表单方式 3.利用ph…...

Xcode手动安装SDK模拟器

1.下载SDK模拟器&Xcode SDK和Xcode官方下载地址 2.下载好后使用命令将SDK导入到Xcode中如下命令 注&#xff1a;我是在/Applications 目录下执行的命令&#xff0c;模拟其地址直接拖拽过来 sudo xcode-select -s Xcode.app xcodebuild -runFirstLaunch xcodebuild -imp…...

Docker安装consul + go使用consul + consul知识

1. 什么是服务注册和发现 假如这个产品已经在线上运行&#xff0c;有一天运营想搞一场促销活动&#xff0c;那么我们相对应的【用户服务】可能就要新开启三个微服务实例来支撑这场促销活动。而与此同时&#xff0c;作为苦逼程序员的你就只有手动去 API gateway 中添加新增的这…...

JWT 漏洞 - 学习手册

0x01&#xff1a;JWT 前导知识 0x0101&#xff1a;JWT 详解 0x02&#xff1a;JWT 漏洞介绍 0x0201&#xff1a;JWT 漏洞介绍 0x03&#xff1a;JWT 挖掘思路 JWT 漏洞挖掘思路 - JWT Payload 敏感信息泄露 备注&#xff1a;通过泄露的 JWT Payload 获取用户的敏感信息&#…...

HTML【知识改变命运】03font 字体标签

题目&#xff1a;在页面上显示"北京"两个字&#xff0c;字体为微软雅黑&#xff0c;颜色为红色&#xff0c;大小为40xp&#xff1b; font标签可以修饰字体的大小&#xff0c;颜色&#xff0c;和字体 属性&#xff1a;color颜色&#xff0c;face字体&#xff0c;size大…...

集师专属知识付费小程序搭建 心理咨询小程序搭建

一、产品简介 集师SaaS知识付费软件&#xff0c;为知识创业者或商家提供一站式内容交付解决方案&#xff0c;助力商家搭建集品牌传播、商业变现和用户运营于一体的线上知识服务系统&#xff0c;覆盖全渠道经营场景&#xff0c;占据每个流量入口&#xff0c;使流量变现快速高效…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...