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
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83790.shtml
英文地址,請注明出處:http://en.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單元格行、列號獲取(實例:表格選與維度轉換)學習筆記

************************************************************************************************************** 點擊進入 -我要自學網-國內領先的專業視頻教程學習網站 *******************************************************************************************…