Qt多线程访问同一个数据库源码分享(基于Sqlite实现)

Qt多线程访问同一个数据库源码分享(基于Sqlite实现)

  • 一、实现难点
    • 线程安全问题
    • 死锁风险
    • 连接管理问题
    • 数据一致性
    • 性能瓶颈
    • 跨线程信号槽
    • 最佳实践建议
  • 二、源码分享
  • 三、测试
    • 1、新建一个多线程类
    • 2、开启多线程插入数据

一、实现难点

多线程环境下多个线程同时访问同一个数据库会面临以下主要难点:

线程安全问题

数据库连接对象通常不是线程安全的,多个线程同时使用同一个连接会导致数据混乱或崩溃。每个线程需要独立的数据库连接。

死锁风险

多个线程同时执行事务操作时,如果锁定顺序不一致可能导致死锁。需要统一锁定顺序或使用超时机制。

连接管理问题

频繁创建和销毁连接会导致性能问题。可以使用连接池管理数据库连接。

数据一致性

多线程并发写入可能导致数据不一致。需要合理使用事务隔离级别和锁机制。

性能瓶颈

过多线程同时访问可能导致数据库成为性能瓶颈。需要限制最大并发线程数。

跨线程信号槽

Qt要求数据库对象必须在创建它的线程中使用。跨线程操作需要特别注意。

最佳实践建议

使用Qt的线程模块时,遵循以下原则可减少问题:

  • 每个线程使用独立的数据库连接
  • 合理使用事务和锁机制
  • 考虑使用连接池管理连接
  • 控制最大并发线程数
  • 避免跨线程传递数据库对象

商业数据库通常提供更好的多线程支持,SQLite等嵌入式数据库在多线程环境下需要特别注意。### 多线程数据库访问的难点

二、源码分享

由于多个线程访问同一个数据库所以用一个单例类来管理数据库,实现如下:

sqliteHelper.h

#ifndef SQLITEHELPER_H
#define SQLITEHELPER_H#include <QObject>
#include <QtSql>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include <QQueue>
#include <QThread>class SqliteHelper
{
private:SqliteHelper();SqliteHelper(SqliteHelper& ) = delete;SqliteHelper operator=(const SqliteHelper &) = delete;
public:~SqliteHelper();static SqliteHelper *getInstance();static void changeDatabase(QString databaseName);bool lockExec(QString sql);QSqlDatabase *getDatabase();static void quit();
private:static void removeDatabases();
private:static QMutex mutexCreateSql,mutexUpdateSql;QString strConnName;static QString currentDatabaseName;static QHash<Qt::HANDLE, SqliteHelper*> databaseMap;//所有数据库链接,key: 线程ID,
};#endif // SQLITEHELPER_H

sqliteHelper.cpp

#include "sqliteHelper.h"QMutex SqliteHelper::mutexCreateSql;
QMutex SqliteHelper::mutexUpdateSql;
QHash<Qt::HANDLE, SqliteHelper*> SqliteHelper::databaseMap;
QString SqliteHelper::currentDatabaseName;SqliteHelper::SqliteHelper()
{mutexCreateSql.lock();Qt::HANDLE id = QThread::currentThreadId();strConnName = QString::number(*(unsigned int*)&id);QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE", strConnName);database.setDatabaseName(currentDatabaseName);qDebug()<<"SQLiteHelper()  "<<strConnName;mutexCreateSql.unlock();
}SqliteHelper::~SqliteHelper()
{}SqliteHelper *SqliteHelper::getInstance()
{if(!databaseMap.contains(QThread::currentThreadId())) {databaseMap.insert(QThread::currentThreadId(), new SqliteHelper());}return databaseMap[QThread::currentThreadId()];
}void SqliteHelper::changeDatabase(QString databaseName)
{if(databaseName.isEmpty())return;SqliteHelper::removeDatabases();currentDatabaseName = databaseName;qDebug()<<databaseName;
}bool SqliteHelper::lockExec(QString sql)
{mutexUpdateSql.lock();QSqlDatabase sqlDb =QSqlDatabase::database(strConnName);if(!sqlDb.isOpen()){mutexCreateSql.lock();sqlDb.open();mutexCreateSql.unlock();}QSqlQuery sqlQuery(sqlDb);sqlQuery.prepare(sql);bool res = sqlQuery.exec();if(!res)qDebug()<<sqlQuery.lastError().text();sqlDb.close();mutexUpdateSql.unlock();return res;
}
QSqlDatabase *SqliteHelper::getDatabase()
{QSqlDatabase *sqlDb = new QSqlDatabase(QSqlDatabase::database(strConnName));if(!sqlDb->isOpen()){mutexCreateSql.lock();sqlDb->open();mutexCreateSql.unlock();}return sqlDb;
}void SqliteHelper::quit()
{currentDatabaseName = "";removeDatabases();
}void SqliteHelper::removeDatabases()
{qDebug()<<"SQLiteHelper::removeDatabases()";QList<Qt::HANDLE> keys = databaseMap.keys();for(int i= 0; i<keys.count();i++){Qt::HANDLE id = keys[i];//释放内存delete databaseMap.take(id);QSqlDatabase::removeDatabase(QString::number(*(unsigned int*)&id));}
}

三、测试

1、新建一个多线程类

thread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include <QObject>
#include <QString>#include "sqlitehelper.h"class MyThread:public QThread
{
public:MyThread();public:void run() override;
};#endif // MYTHREAD_H

thread.cpp

#include "mythread.h"MyThread::MyThread()
{}void MyThread::run()
{static int cnt = 0;while(1){QThread::sleep(1);auto id = QThread::currentThreadId();int barCode = 0, waybillCode = 0;barCode = *(unsigned int*)&id + cnt;waybillCode = *(unsigned int*)&id + cnt;cnt++;QString sql = QString(R"(INSERT INTO produceTable(barCode,waybillCode,dateTime) VALUES('%1','%2',datetime(CURRENT_TIMESTAMP, 'localtime'));)").arg("barCode"+QString::number(barCode)).arg("waybillCode"+QString::number(waybillCode));SqliteHelper* sqlHelper = SqliteHelper::getInstance();qDebug()<<id<<"  "<<sqlHelper->lockExec(sql);}}

2、开启多线程插入数据

连接一个数据库:

SqliteHelper::changeDatabase("database2.db");

界面中放置一个按钮,按几下开启几个线程。

void MainWindow::on_btnInsertData_clicked()
{MyThread *t = new MyThread();t->start();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双空间知识蒸馏用于大语言模型

Dual-Space Knowledge Distillation for Large Language Models 发表&#xff1a;EMNLP 2024 机构&#xff1a;Beijing Key Lab of Traffic Data Analysis and Mining 连接&#xff1a;https://aclanthology.org/2024.emnlp-main.1010.pdf 代码&#xff1a;GitHub - songmz…

贪心算法应用:多重背包启发式问题详解

贪心算法应用&#xff1a;多重背包启发式问题详解 多重背包问题是经典的组合优化问题&#xff0c;也是贪心算法的重要应用场景。本文将全面深入地探讨Java中如何利用贪心算法解决多重背包问题。 多重背包问题定义 **多重背包问题(Multiple Knapsack Problem)**是背包问题的变…

ES6 Promise 状态机

状态机&#xff1a;抽象的计算模型&#xff0c;根据特定的条件或者信号切换不同的状态 一、Promise 是什么&#xff1f; 简单来说&#xff0c;Promise 就是一个“承诺对象”。在ES6 里&#xff0c;有些代码执行起来需要点时间&#xff0c;比如加载文件、等待网络请求或者设置…

【Docker管理工具】部署Docker可视化管理面板Dpanel

【Docker管理工具】部署Docker可视化管理面板Dpanel 一、Dpanel介绍1.1 DPanel 简介1.2 主要特点 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Dpanel镜像五、部署Dpanel…

最新研究揭示云端大语言模型防护机制的成效与缺陷

一项全面新研究揭露了主流云端大语言模型&#xff08;LLM&#xff09;平台安全机制存在重大漏洞与不一致性&#xff0c;对当前人工智能安全基础设施现状敲响警钟。该研究评估了三大领先生成式AI平台的内容过滤和提示注入防御效果&#xff0c;揭示了安全措施在阻止有害内容生成与…

docker中,容器时间和宿机主机时间不一致问题

win11下的docker中有个mysql。今天发现插入数据的时间不正确。后来发现原来是docker容器中的时间不正确。于是尝试了各种修改&#xff0c;什么run -e TZ"${tzutil /g}"&#xff0c;TZ"Asia/Shanghai"&#xff0c;还有初始化时带--mysqld一类的&#xff0c;…

uniapp实现的简约美观的星级评分组件

采用 uniapp 实现的一款简约美观的星级评分模板&#xff0c;提供丝滑动画效果&#xff0c;用户可根据自身需求进行自定义修改、扩展&#xff0c;纯CSS、HTML实现&#xff0c;支持web、H5、微信小程序&#xff08;其他小程序请自行测试&#xff09; 可到插件市场下载尝试&#x…

go语言的锁

本篇文章主要讲锁&#xff0c;主要会涉及go的sync.Mutex和sync.RWMutex。 一.锁的概念和发展 1.1 锁的概念 所谓的加锁和解锁其实就是指一个数据是否被占用了&#xff0c;通过Mutex内的一个状态来表示。 例如&#xff0c;取 0 表示未加锁&#xff0c;1 表示已加锁&#xff…

Ubuntu 服务器软件更新,以及常用软件安装 —— 一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录 3

前言 前面&#xff0c;我们已经 安装好了 Ubuntu 服务器系统&#xff0c;并且 配置好了 ssh 免密登录服务器 &#xff0c;现在&#xff0c;我们要来进一步的设置服务器。 那么&#xff0c;本文&#xff0c;就是进行服务器的系统更新&#xff0c;以及常用软件的安装 调整 Ubu…

如何从零开始建设一个网站?

当你没有建站的基础和建站的知识&#xff0c;那么应该如何开展网站建设和网站管理。而今天的教程是不管你是为自己建站还是为他人建站都适合的。本教程会指导你如何进入建站&#xff0c;将建站的步骤给大家分解&#xff1a; 首先我们了解一下&#xff0c;建站需要那些步骤和流程…

网络可靠性的定义与核心要素

网络可靠性&#xff08;Network Reliability&#xff09;是指网络系统在特定时间范围内持续提供稳定、无中断、符合预期性能的服务能力。其核心目标是确保数据能够准确、完整、及时地传输&#xff0c;即使在部分故障或异常情况下仍能维持基本功能。 1. 网络可靠性的核心指标 衡…

GpuGeek如何成为AI基础设施市场的中坚力量

AI时代&#xff0c;算力基础设施已成为支撑技术创新和产业升级的关键要素。作为国内专注服务算法工程师群体的智算平台&#xff0c;GpuGeek通过持续创新的服务模式、精准的市场定位和系统化的生态建设&#xff0c;正快速成长为AI基础设施领域的中坚力量。本文将深入分析GpuGeek…

【Qt】Bug:findChildren找不到控件

使用正确的父对象调用 findChildren&#xff1a;不要在布局对象上调用 findChildren&#xff0c;而应该在布局所在的窗口或控件上调用。

【Linux网络编程】传输层协议TCP,UDP

目录 一&#xff0c;UDP协议 1&#xff0c;UDP协议的格式 2&#xff0c;UDP的特点 3&#xff0c;面向数据报 4&#xff0c;UDP的缓冲区 5&#xff0c;UDP使用注意事项 6&#xff0c;基于UDP的应用层协议 二&#xff0c;对于报文的理解 三&#xff0c;TCP协议 1&…

Neo4j 数据可视化与洞察获取:原理、技术与实践指南

在关系密集型数据的分析领域,Neo4j 凭借其强大的图数据模型脱颖而出。然而,将复杂的连接关系转化为直观见解,需要专业的数据可视化技术和分析方法。本文将深入探讨 Neo4j 数据可视化的核心原理、关键技术、实用技巧以及结合图数据科学库(GDS)获取深度洞察的最佳实践。 Ne…

树莓派超全系列教程文档--(55)如何使用网络文件系统NFS

如何使用网络文件系统NFS 网络文件系统 (NFS)设置基本 NFS 服务器Portmap 锁定&#xff08;可选&#xff09; 配置 NFS 客户端端口映射锁定&#xff08;可选&#xff09; 配置复杂的 NFS 服务器组权限DNS&#xff08;可选&#xff0c;仅在使用 DNS 时&#xff09;NIS&#xff0…

无法运用pytorch环境、改环境路径、隔离环境

一.未建虚拟环境时 1.创建新项目后&#xff0c;直接运行是这样的。 2.设置中Virtualenv找不到pytorch环境&#xff1f;因为此时没有创建新虚拟环境。 3.选择conda环境&#xff08;全局环境&#xff09;时&#xff0c;是可以下载环境的。 运行结果如下&#xff1a; 是全局环境…

HTML5+CSS3+JS小实例:具有粘性重力的磨砂玻璃导航栏

实例:具有粘性重力的磨砂玻璃导航栏 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width…

NodeJS全栈WEB3面试题——P8项目实战类问题(偏全栈)

&#x1f4e6; 8.1 请描述你做过的 Web3 项目&#xff0c;具体技术栈和你负责的模块&#xff1f; 我主导开发过一个基于 NFT 的数字纪念平台&#xff0c;用户可以上传照片并生成独特的纪念 NFT&#xff0c;结合 IPFS 和 ERC-721 实现永存上链。 &#x1f527; 技术栈&#xf…

3-10单元格行、列号获取(实例:表格选与维度转换)学习笔记

************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…