基于Qt封装数据库基本增删改查操作,支持多线程,并实现SQLite数据库单例访问

news2025/6/3 21:39:43

抽出来的,直接用就行

  • 头文件
  • CPP文件
  • 使用示例

头文件

#ifndef DATABASECOMMON_H
#define DATABASECOMMON_H

/*
 * 单例封装SQLite通用操作,支持多线程调用;可扩展兼容其他数据库,照着SysRunDatabase写,并且重载openDatabase即可
 * 使用步骤:1、主线程addDatabase,调用setDatabase
 *         2、setDatabaseName
 *         3、按需setUserName、setPassword
 *         4、openDatabase
 *         5、查询使用execSelect,建表使用execNormalSQL,插入、修改、删除等操作使用execTransaction
 *         6、closeDatabase(程序生命周期内不需要显式调用,这里仅预留)
*/

#include <QObject>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QMutex>
/*
  * 类名:DatabaseCommon
  * 功能:数据库基础操作抽象类,由子类实现openDatabase操作
  * 使用方法:子类化DatabaseCommon,并实现openDatabase函数
*/
class DatabaseCommon
    : public QObject
{
    Q_OBJECT
public:
    void setDatabase(QSqlDatabase db);
    void setDatabaseName(QString dbName);
    void setUserName(QString userName);
    void setPassword(QString password);
    virtual bool openDatabase() = 0;//不同数据库的打开方式不同
    void closeDatabase();
    bool execNormalSQL(const QString &sqlString);
    bool execSelect(const QString &sqlString, QSqlQueryModel &model);
    bool execTransaction(const QString &sqlString);
    bool execTransaction(const QStringList &sqlStrings);
private:
    DatabaseCommon(const DatabaseCommon&) = delete;
    DatabaseCommon& operator=(const DatabaseCommon&) = delete;
protected:
    explicit DatabaseCommon(QObject *parent = nullptr){}
    virtual ~DatabaseCommon();
    QSqlDatabase mDatabase;
    QString mDatabaseName = "";
    QString mUserName = "";
    QString mPassword = "";
    QMutex mMutex;//保证多线程访问安全
};
/*
  * 类名:SysRunDatabase
  * 功能:应用于SysRun.db数据库,使用全局单例进行访问
*/
class SysRunDatabase : public DatabaseCommon
{
    Q_OBJECT
public:
    static SysRunDatabase& Instance()
    {
        static SysRunDatabase mInstance;
        return mInstance;
    }
    bool openDatabase() override;
protected:
    explicit SysRunDatabase(QObject *parent = nullptr){}
    ~SysRunDatabase() override {}
private:
    SysRunDatabase(const SysRunDatabase&) = delete;
    SysRunDatabase& operator=(const SysRunDatabase&) = delete;
};

#endif // DATABASECOMMON_H

CPP文件

#include "databasecommon.h"
#include <QDebug>
#include <QSqlQuery>
#include <QFile>
#include <QException>
#include <QSqlError>
#include <QMutexLocker>

DatabaseCommon::~DatabaseCommon()
{
    closeDatabase();
}
/*
 * 函数名称:setDatabase
 * 功能说明:设置数据库对象
 * 输入参数:数据库对象
 * 输出参数:无
 * 其他说明:无
 */
void DatabaseCommon::setDatabase(QSqlDatabase db)
{
    QMutexLocker locker(&mMutex);
    this->mDatabase = db;
}
/*
 * 函数名称:setDatabaseName
 * 功能说明:设置数据库名称(对于SQLite,就是db文件路径)
 * 输入参数:数据库名称
 * 输出参数:无
 * 其他说明:无
 */
void DatabaseCommon::setDatabaseName(QString dbName)
{
    QMutexLocker locker(&mMutex);
    this->mDatabaseName = dbName;
}
/*
 * 函数名称:setUserName
 * 功能说明:设置数据库用户名
 * 输入参数:用户名
 * 输出参数:无
 * 其他说明:无
 */
void DatabaseCommon::setUserName(QString userName)
{
    QMutexLocker locker(&mMutex);
    this->mUserName = userName;
}
/*
 * 函数名称:setPassword
 * 功能说明:设置数据库用户密码
 * 输入参数:用户密码
 * 输出参数:无
 * 其他说明:无
 */
void DatabaseCommon::setPassword(QString password)
{
    QMutexLocker locker(&mMutex);
    this->mPassword = password;
}
/*
 * 函数名称:openDatabase
 * 功能说明:打开数据库连接
 * 输入参数:无
 * 输出参数:无
 * 其他说明:无
 */
bool SysRunDatabase::openDatabase()
{
    QMutexLocker locker(&mMutex);
    if(!QFile::exists(mDatabaseName))
    {
        qCritical() << "not exist " << mDatabaseName;
        return false;
    }
    mDatabase.setDatabaseName(mDatabaseName);
    mDatabase.setUserName(mUserName);
    mDatabase.setPassword(mPassword);
    if(!mDatabase.open())
    {
        qCritical() << "open failed."<< mDatabase.lastError().text();
        return false;
    }
    return true;
}
/*
 * 函数名称:closeDatabase
 * 功能说明:关闭数据库连接
 * 输入参数:无
 * 输出参数:无
 * 其他说明:无
 */
void DatabaseCommon::closeDatabase()
{
    mDatabase.close();
}
/*
 * 函数名称:execNormalSQL
 * 功能说明:执行通用SQL语句(SELECT除外)
 * 输入参数:SQL语句
 * 输出参数:无
 * 其他说明:无
 */
bool DatabaseCommon::execNormalSQL(const QString &sqlString)
{
    QMutexLocker locker(&mMutex);
    if(!mDatabase.isOpen())
    {
        qCritical() << "Database is closed.";
        return false;
    }
    try
    {
        QSqlQuery query(mDatabase);
        if (!query.exec(sqlString))
        {
            throw query.lastError();
        }
        return true;
    }
    catch (const QSqlError &error)
    {
        qCritical() << "Error:" << error.text();
        return false;
    }
}
/*
 * 函数名称:execSelect
 * 功能说明:执行DQL语句(即SELECT)
 * 输入参数:SELECE语句
 * 输出参数:查询模型,获取结果
 * 其他说明:无
 */
bool DatabaseCommon::execSelect(const QString &sqlString, QSqlQueryModel &model)
{
    QMutexLocker locker(&mMutex);
    if(!mDatabase.isOpen())
    {
        qCritical() << "Database is closed.";
        return false;
    }
    if(!sqlString.startsWith("SELECT", Qt::CaseInsensitive))
    {
        qCritical() << "Unsupported operation: " << sqlString;
        return false;
    }
    try
    {
        model.setQuery(sqlString, mDatabase);
        return true;
    }
    catch (const QException &ex)
    {
        qCritical() << "Exception on model.setQuery: " << ex.what();
        qCritical() << model.lastError().text();
        return false;
    }
}
/*
 * 函数名称:execTransaction
 * 功能说明:基于事务执行SQL语句(SELETE除外)
 * 输入参数:单个SQL语句
 * 输出参数:无
 * 其他说明:无
 */
bool DatabaseCommon::execTransaction(const QString &sqlString)
{
    QMutexLocker locker(&mMutex);
    if(!mDatabase.isOpen())
    {
        qCritical() << "Database is closed.";
        return false;
    }
    if(sqlString.startsWith("SELECT", Qt::CaseInsensitive))
    {
        qCritical() << "Unsupported operation: " << sqlString;
        return false;
    }
    if (!mDatabase.transaction())
    {
        qCritical() << "Failed to begin transaction:" << mDatabase.lastError().text();
        return false;
    }

    QSqlQuery query(mDatabase);

    try
    {
        if (!query.exec(sqlString))
        {
            throw query.lastError();
        }

        // 可选:检查受影响行数
        if (sqlString.trimmed().startsWith("UPDATE", Qt::CaseInsensitive) && query.numRowsAffected() == 0)
        {
            qWarning() << "Warning: No rows affected by:" << sqlString;
        }
        if (!mDatabase.commit())
        {
            throw mDatabase.lastError();
        }

        return true;
    }
    catch (const QSqlError &error)
    {
        if (!mDatabase.rollback())
        {
            qCritical() << "Failed to rollback transaction:" << mDatabase.lastError().text();
        }

        qCritical() << "Transaction failed at command:" << query.lastQuery();
        qCritical() << "Error:" << error.text();
        return false;
    }
}
/*
 * 函数名称:execTransaction
 * 功能说明:基于事务执行SQL语句(SELETE除外)
 * 输入参数:多个SQL语句
 * 输出参数:无
 * 其他说明:无
 */
bool DatabaseCommon::execTransaction(const QStringList &sqlStrings)
{
    QMutexLocker locker(&mMutex);
    if(!mDatabase.isOpen())
    {
        qCritical() << "Database is closed.";
        return false;
    }
    if (!mDatabase.transaction())
    {
        qCritical() << "Failed to begin transaction:" << mDatabase.lastError().text();
        return false;
    }

    QSqlQuery query(mDatabase);

    try
    {
        foreach (const QString &sql, sqlStrings)
        {
            if (!query.exec(sql))
            {
                throw query.lastError();
            }

            // 可选:检查受影响行数
            if (sql.trimmed().startsWith("UPDATE", Qt::CaseInsensitive) && query.numRowsAffected() == 0)
            {
                qWarning() << "Warning: No rows affected by:" << sql;
            }
        }

        if (!mDatabase.commit())
        {
            throw mDatabase.lastError();
        }

        return true;
    }
    catch (const QSqlError &error)
    {
        if (!mDatabase.rollback())
        {
            qCritical() << "Failed to rollback transaction:" << mDatabase.lastError().text();
        }

        qCritical() << "Transaction failed at command:" << query.lastQuery();
        qCritical() << "Error:" << error.text();
        return false;
    }
}

使用示例

QSqlDatabase::addDatabase("QSQLITE", "SysRun");//SysRun是数据库连接名
SysRunDatabase::Instance().setDatabase(QSqlDatabase::database("SysRun", false));
SysRunDatabase::Instance().setDatabaseName("123.db");//123.db是数据库文件名
/*打开数据库连接*/
if(!SysRunDatabase::Instance().openDatabase())
{
	return false;
}
//在此之后就可以增删改查

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

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

相关文章

EC800X QuecDuino开发板介绍

支持的模组列表 EG800KEC800MEC800GEC800E 功能列表 基本概述 EC800X QuecDuino EVB 搭载移远 EC800 系列模组。支持模组型号为&#xff1a; EC800M 系列、EC800K 系列、EG800K 系列、EC800E 系列等。 渲染图 开发板的主要组件、接口布局见下图 资料下载 EC800X-QuecDui…

PHP轻量级聊天室源码(源码下载)

最新版本&#xff1a;v2.1.2 (2024.08更新) 运行环境&#xff1a;PHP5.6&#xff08;无需MySQL&#xff09; 核心特性&#xff1a;手机电脑自适应、TXT数据存储、50条历史消息 适用场景&#xff1a;小型社区/企业内网/教育培训即时通讯 一、核心功能亮点&#xff08;SEO关键词布…

leetcode hot100刷题日记——33.二叉树的层序遍历

解题总结二维vector的初始化方法 题目描述情况1&#xff1a;不确定行数和列数情况2&#xff1a;已知行数和列数情况3&#xff1a;已知行数但不知道列数情况4&#xff1a;已知列数但不知道行数 题目描述 解答&#xff1a;用队列 思路都差不多&#xff0c;我觉得对于我自己来说&a…

《数据结构初阶》【番外篇:快速排序的前世今生】

【番外篇&#xff1a;快速排序的前世今生】目录 前言&#xff1a;---------------起源---------------一、诞生&#xff1a;二、突破&#xff1a;三、核心&#xff1a; ---------------发展---------------1. 早期版本&#xff1a;简单但不稳定1960 年&#xff1a;初始版本 2. …

【笔记】基于 MSYS2(MINGW64)的 Poetry 虚拟环境创建指南

#工作记录 基于 MSYS2&#xff08;MINGW64&#xff09;的 Poetry 虚拟环境创建指南 一、背景说明 在基于 MSYS2&#xff08;MINGW64&#xff09;的环境中&#xff0c;使用 Poetry 创建虚拟环境是一种高效且灵活的方式来管理 Python 项目依赖。本指南将详细介绍如何在 PyChar…

PINNs案例——二维磁场计算

基于物理信息的神经网络是一种解决偏微分方程计算问题的全新方法… 有关PINN基础详见&#xff1a;PINNs案例——中心热源温度场预测问题的torch代码 今日分享代码案例&#xff1a;二维带电流源磁场计算 该案例参考学习论文&#xff1a;[1]张宇娇&#xff0c;孙宏达&#xff0…

算法打开13天

41.前 K 个高频元素 &#xff08;力扣347题&#xff09; 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: …

广告拦截器:全方位拦截,畅享无广告体验

在数字时代&#xff0c;广告无处不在。无论是浏览网页、使用社交媒体&#xff0c;还是观看视频&#xff0c;广告的频繁弹出常常打断我们的体验&#xff0c;让人不胜其烦。更令人担忧的是&#xff0c;一些广告可能包含恶意软件&#xff0c;威胁我们的设备安全和个人隐私。AdGuar…

主数据编码体系全景解析:从基础到高级的编码策略全指南

在数字化转型的浪潮中&#xff0c;主数据管理&#xff08;MDM&#xff09;已成为企业数字化转型的基石。而主数据编码作为MDM的核心环节&#xff0c;其设计质量直接关系到数据管理的效率、系统的可扩展性以及业务决策的准确性。本文将系统性地探讨主数据编码的七大核心策略&…

Selenium操作指南(全)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大家好&#xff0c;今天带大家一起系统的学习下模拟浏览器运行库Selenium&#xff0c;它是一个用于Web自动化测试及爬虫应用的重要工具。 Selenium测试直接运行在…

智绅科技——科技赋能健康养老,构建智慧晚年新生态

当老龄化浪潮与数字技术深度碰撞&#xff0c;智绅科技以 “科技赋能健康&#xff0c;智慧守护晚年” 为核心理念&#xff0c;锚定数字健康与养老服务赛道&#xff0c;通过人工智能、物联网、大数据等技术集成&#xff0c;为亚健康群体与中老年人群构建 “监测 - 预防 - 辅助 - …

STM32通过KEIL pack包轻松移植LVGL,并学会使用GUI guider

先展示最终实现的功能效果如下&#xff1a; 1.目的与意义 之前在学习STM32移植LVGL图形库的时候&#xff0c;搜到的很多教程都是在官网下载LVGL的文件包&#xff0c;然后一个个文件包含进去&#xff0c;还要添加路径&#xff0c;还要给文件改名字&#xff0c;最后才能修改程序…

SQL的查询优化

1. 查询优化器 1.1. SQL语句执行需要经历的环节 解析阶段&#xff1a;语法分析和语义检查&#xff0c;确保语句正确&#xff1b;优化阶段&#xff1a;通过优化器生成查询计划&#xff1b;执行阶段&#xff1a;由执行器根据查询计划实际执行操作。 1.2. 查询优化器 查询优化器…

MCU如何从向量表到中断服务

目录 1、中断向量表 2、编写中断服务例程 中断处理的核心是中断向量表&#xff08;IVT&#xff09;&#xff0c;它是一个存储中断服务例程&#xff08;ISR&#xff09;地址的内存结构。当中断发生时&#xff0c;MCU通过IVT找到对应的ISR地址并跳转执行。本文将深入探讨MCU&am…

Linux线程同步实战:多线程程序的同步与调度

个人主页&#xff1a;chian-ocean 文章专栏-Linux Linux线程同步实战&#xff1a;多线程程序的同步与调度 个人主页&#xff1a;chian-ocean文章专栏-Linux 前言&#xff1a;为什么要实现线程同步线程饥饿&#xff08;Thread Starvation&#xff09;示例&#xff1a;抢票问题 …

【MySQL】事务及隔离性

目录 一、什么是事务 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;事务的四大属性 &#xff08;三&#xff09;事务的作用 &#xff08;四&#xff09;事务的提交方式 二、事务的启动、回滚与提交 &#xff08;一&#xff09;事务的启动、回滚与提交 &am…

yolo目标检测助手:具有模型预测、图像标注功能

在人工智能浪潮席卷各行各业的今天&#xff0c;计算机视觉模型&#xff08;如 YOLO&#xff09;已成为目标检测领域的标杆。然而&#xff0c;模型的强大能力需要直观的界面和便捷的工具才能充分发挥其演示、验证与迭代优化的价值。为此&#xff0c;我开发了一款基于 WPF 的桌面…

2022 RoboCom 世界机器人开发者大赛(睿抗 caip) -高职组(国赛)解题报告 | 科学家

前言 题解 2022 RoboCom 世界机器人开发者大赛(睿抗 caip) -高职组&#xff08;国赛&#xff09;。 最后一题还考验能力&#xff0c;需要找到合适的剪枝。 RC-v1 智能管家 分值: 20分 签到题&#xff0c;map的简单实用 #include <bits/stdc.h>using namespace std;int…

基于物联网(IoT)的电动汽车(EVs)智能诊断

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 做到欲望极简&#xff0c;了解自己的真实欲望&#xff0c;不受外在潮流的影响&#xff0c;不盲从&#x…

JDBC+HTML+AJAX实现登陆和单表的CRUD

JDBCHTMLAJAX实现登陆和单表的CRUD 导入maven依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocatio…