QT实现sqlite数据库连接池

2023-10-26

#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H
/*****************************************************************************
**FileName: 数据库连接池
**Function: 获取连接时不需要了解连接的名字
支持多线程,保证获取到的连接一定是没有被其他线程正在使用
按需创建连接
可以创建多个连接
可以控制连接的数量
连接被复用,不是每次都重新创建一个新的连接
连接断开了后会自动重连
当无可用连接时,获取连接的线程会等待一定时间尝试继续获取,直到超时才会返回一个无效的连接

**Version record:
**Version       Author         Data          Description
**v1.0.1        wlj   2019.05.16        first draft
*******************************************************************************/

#include<QtSql>
#include<QQueue>
#include<QString>
#include<QMutex>
#include<QMutexLocker>

class ConnectionPool
{
public:
    ~ConnectionPool();
    /******************************************************************************
* Function: 参数设置
* InPut   : databaseName数据库名称 databaseType数据库类型 hostName端口号
* OutPut  :无
* Return  :无
* Other   :
* Author  : wlj   2019.05.22
*******************************************************************************/
    static void SetParam(QString databaseName,QString databaseType,QString hostName = "");
    /******************************************************************************
* Function:   从连接池里获取连接
* InPut   : 无
* OutPut  : 无
* Return  : 返回获取到的链接db
* Other   : OpenConnection-CloseConnection要成对使用
* Author  : wlj   2019.05.22
*******************************************************************************/
    static QSqlDatabase OpenConnection();//用于从连接池里获取连接
    /******************************************************************************
* Function:   连接释放回连接池
* InPut   : connection数据库链接
* OutPut  : 无
* Return  : 无
* Other   : 并不会真正的关闭连接,而是把连接放回连接池复用;OpenConnection-CloseConnection要成对使用
* Author  : wlj   2019.05.22
*******************************************************************************/
    static void CloseConnection(QSqlDatabase connection);//并不会真正的关闭连接,而是把连接放回连接池复用。

private:
    ConnectionPool();
    static ConnectionPool& GetInstance();
    static void Release();//真正的关闭所有的连接
    ConnectionPool(const ConnectionPool &){}
    ConnectionPool& operator=(const ConnectionPool &);
    QSqlDatabase CreateConnection(const QString &connectionName); // 创建数据库连接
    class GarbageCollector
    {
    public:
        ~GarbageCollector()
        {
            ConnectionPool::Release();
        }
    };

private:
    static GarbageCollector m_gc;          //静态变量,只是为了释放单例

    QQueue<QString> m_UsedConnectionNames;   // 已使用的数据库连接名
    QQueue<QString> m_UnusedConnectionNames; // 未使用的数据库连接名

    // 数据库信息
    QString m_HostName;
    QString m_DatabaseName;// 如果是 SQLite 则为数据库文件名
    //    QString m_Username;// 如果是 SQLite 不需要
    //    QString m_Password;// 如果是 SQLite 不需要
    QString m_DatabaseType;

    bool    m_TestOnBorrow;    // 取得连接的时候验证连接是否有效
    QString m_TestOnBorrowSql; // 测试访问数据库的 SQL

    int m_MaxWaitTime;  // 获取连接最大等待时间
    int m_WaitInterval; // 尝试获取连接时等待间隔时间
    int m_MaxConnectionCount; // 最大连接数

    static QMutex m_Mutex;
    static QWaitCondition m_WaitConnection;
    static ConnectionPool *m_Instance;
};

#endif // CONNECTIONPOOL_H
#include "connectionpool.h"
#include <QDebug>

#define HOSTNAME "127.0.0.1"
#define DATABASENAME "ChatMsg/ChatMsg.db"
#define DATABASETYPE "QSQLITE"
#define TESTONBORROWSQL "SELECT 1"
#define MAXWAITTIME 1000
#define WAITINTERVAL 200
#define MAXCONNECTIONCOUNT 50

QMutex ConnectionPool::m_Mutex;
QWaitCondition ConnectionPool::m_WaitConnection;
ConnectionPool::GarbageCollector ConnectionPool::m_gc;
ConnectionPool* ConnectionPool::m_Instance = NULL;

ConnectionPool::ConnectionPool()
{
    qDebug()<<"ConnectionPool::ConnectionPool";
    m_HostName = HOSTNAME;
    m_DatabaseName =  QCoreApplication::applicationDirPath() + "//" + DATABASENAME;
    m_DatabaseType = DATABASETYPE;
    m_TestOnBorrow = true;
    m_TestOnBorrowSql = TESTONBORROWSQL;

    m_MaxWaitTime = MAXWAITTIME;
    m_WaitInterval = WAITINTERVAL;
    m_MaxConnectionCount = MAXCONNECTIONCOUNT;
}
ConnectionPool::~ConnectionPool()
{
    foreach(QString connectionName, m_UsedConnectionNames)
    {
        QSqlDatabase::removeDatabase(connectionName);
    }

    foreach(QString connectionName, m_UnusedConnectionNames)
    {
        QSqlDatabase::removeDatabase(connectionName);
    }
}

ConnectionPool & ConnectionPool::GetInstance()
{
    if(NULL == m_Instance)
    {
        QMutexLocker locker(&m_Mutex);
        if(NULL == m_Instance)
        {
            m_Instance = new ConnectionPool();
        }
    }
    return *m_Instance;
}

void ConnectionPool::Release()
{
    QMutexLocker locker(&m_Mutex);
    delete m_Instance;
    m_Instance = NULL;
    qDebug()<<"release ConnectionPool::m_Instance";
}
void ConnectionPool::SetParam(QString databaseName,QString databaseType,QString hostName)
{
    ConnectionPool &pool = ConnectionPool::GetInstance();
    pool.m_HostName = hostName;
    pool.m_DatabaseName = databaseName;
    pool.m_DatabaseType = databaseType;
}
QSqlDatabase ConnectionPool::OpenConnection()
{
    ConnectionPool &pool = ConnectionPool::GetInstance();
    QString connectionName;

    QMutexLocker locker(&m_Mutex);

    // 已创建连接数
    int connectionCount = pool.m_UnusedConnectionNames.size() + pool.m_UsedConnectionNames.size();

    // 如果连接已经用完,等待 waitInterval 毫秒看看是否有可用连接,最长等待 maxWaitTime 毫秒
    for(int i = 0; (i < pool.m_MaxWaitTime)
        && (pool.m_UnusedConnectionNames.size() == 0)
        && (connectionCount == pool.m_MaxConnectionCount);
        i += pool.m_WaitInterval)
    {
        m_WaitConnection.wait(&m_Mutex, pool.m_WaitInterval);

        // 重新计算已创建连接数
        connectionCount = pool.m_UnusedConnectionNames.size() + pool.m_UsedConnectionNames.size();
    }
    if(0 < pool.m_UnusedConnectionNames.size() )
    {
        // 有已经回收的连接,复用它们
        connectionName = pool.m_UnusedConnectionNames.dequeue();
    }
    else if(connectionCount < pool.m_MaxConnectionCount)
    {
        // 没有已经回收的连接,但是没有达到最大连接数,则创建新的连接
        connectionName = QString("UserConnection - %1").arg(connectionCount + 1);
    }
    else
    {
        qWarning() << "connectionCount = "<<connectionCount<<"Cannot create more connections.";
        return QSqlDatabase();
    }

    // 创建连接
    QSqlDatabase db = pool.CreateConnection(connectionName);

    // 有效的连接才放入 usedConnectionNames
    if(db.isOpen())
    {
        pool.m_UsedConnectionNames.enqueue(connectionName);
    }
    else
    {
        // 连接无效
        qWarning() << "connections is open fail.";
        return QSqlDatabase();
    }
//qDebug()<<connectionName;
    return db;
}

void ConnectionPool::CloseConnection(QSqlDatabase connection)
{
    ConnectionPool &pool = ConnectionPool::GetInstance();
    QString connectionName = connection.connectionName();

    // 如果是我们创建的连接,从 used 里删除,放入 unused 里
    if(pool.m_UsedConnectionNames.contains(connectionName))
    {
        QMutexLocker locker(&m_Mutex);
        pool.m_UsedConnectionNames.removeOne(connectionName);
        pool.m_UnusedConnectionNames.enqueue(connectionName);
        m_WaitConnection.wakeOne();
    }
}

QSqlDatabase ConnectionPool::CreateConnection(const QString &connectionName)
{
    // 连接已经创建过了,复用它,而不是重新创建
    if(QSqlDatabase::contains(connectionName))
    {
        QSqlDatabase db1 = QSqlDatabase::database(connectionName);

        if(!db1.isOpen())
        {
            // 返回连接前访问数据库,如果连接断开,重新建立连接
//                        qDebug() << "Reconnection: " << m_TestOnBorrowSql << " for " << connectionName;
            QSqlQuery query(m_TestOnBorrowSql, db1);

            if(!db1.open() && QSqlError::NoError != query.lastError().type() )
            {
                qDebug() << "Open datatabase error:" << db1.lastError().text();
                return QSqlDatabase();
            }
        }

        return db1;
    }

    // 创建一个新的连接
    QSqlDatabase db = QSqlDatabase::addDatabase(m_DatabaseType, connectionName);
    //    db.setHostName(m_HostName);
    db.setDatabaseName(m_DatabaseName);

    if (!db.open())
    {
        qDebug() << "Open datatabase error:" << db.lastError().text();
        return QSqlDatabase();
    }

    return db;
}

转自:https://www.cnblogs.com/qk2015/p/4832534.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT实现sqlite数据库连接池 的相关文章

  • Qt Ui 命名空间

    命名空间有什么意义Ui这是Qt自动生成的吗 这两个命名空间相同吗 在第一个中 其中包含 MainWindow 类的前向声明ui MainWindow h为什么它没有声明为class Ui MainWindow 编译器如何知道 MainWin
  • Qt 调试器在 mac 上使用错误的 python 版本

    我使用的是 macOS Mojave 10 14 6 我的Qt版本是5 13 1 我的 Qt Creator 版本是 4 10 0 当我设置断点并运行应用程序时 调试器永远不会完成并打印到调试器日志并显示以下错误 因此 据我所知 lldb
  • 无法在 mac osx 上的 QT 中创建新项目

    过去几天我一直坚持这个问题 我已经安装了 QT 4 8 并且也安装了库 但是当我开始创建一个新项目时 我只能选择使用 CMake 创建一个普通的 C 项目 我没有使用自动 qmake 的选项 我不知道为什么 如果有人可以帮忙 我们将不胜感激
  • 如何使用 qt 在键盘上仅显示数字

    我在我的项目中使用 Qt Quick Virtual Keyboard 当我单击一个对象时 我想显示键盘但只显示数字 我怎样才能做到这一点 这就是我想做的 您可以使用Qt ImhFormattedNumbersOnly http doc q
  • 如何为列表中的每个元素创建一个按钮并将其放在滚动区域中?

    我有一个列表 每次用户打开文件时都会获取一个元素 我需要创建一个带有文件名 列表中的元素 的按钮 每次将该文件附加到列表中时 并将该按钮放入滚动区域 问题是我总是只有一个按钮 只是更改了名称 filenames def addfiles f
  • 如何完全删除 QLayout 的边距(特定于 Mac OS)

    Let me explain a simplified situation In Qt Creator create a QHBoxLayout containing a QPushButton and another QHBoxLayou
  • 将 Objective-C 代码转换为 C++ 以检测 OS X 上的用户空闲时间

    我正在开发 Qt C 应用程序 我需要简单的函数来在 Mac OS X 上以秒为单位检索用户空闲时间 我发现这个代码用于检测用户空闲时间 include
  • 如何在 Qt 中使用 QTabWidget 创建多行选项卡?

    我尝试使用 QTabWidget 创建一个多行选项卡 如下所示 我也设置了tabPosition 南但我不能有多行选项卡 因为所有选项卡都是水平的 所有选项卡都在一行中 而不是多行 这些是我得到的标签 我读过了这个帖子 https stac
  • 如果值包含逗号字符,如何使用 QSetting 读取值[重复]

    这个问题在这里已经有答案了 在我的 QT 项目中 我使用 QSettings 从 ini 文件读取值 如果该值包含逗号字符 QSettings 无法读取它 我应该如何读取这些值 逗号字符被视为列表分隔符QSettings 带逗号的 INI
  • 如何在 QML 中使用 Font Awesome

    有谁知道如何在 QML 中使用 Font Awesome 吗 我找不到任何文档或任何信息如何在 QML 中使用 Font Awesome 我喜欢做的是使用fontello http fontello com 创建最小的图标集 而不是从 Fo
  • 更改 QT 主窗口的标题字体

    我想知道如何更改 QT 主窗口的标题字体 请参阅随附的屏幕截图 我尝试更改样式表等 但它不起作用 我也尝试使用 C 发送消息 但这也有效 SendMessage form gt effectiveWinId WM SETFONT WPARA
  • 如何在 Qt 5 中写入和读取 QResource 文件?

    很奇怪 我通过以下方式将所需的文件添加到资源中添加现有文件 文件就在那里 我运行 qmake 构建 gt 运行 qmake 以使文件可用 第一期 我无法从输出终端向文件写入任何内容 但是当我手动写入文件时 每次运行它时输出终端都会显示更改
  • 无法在Mac上安装qwt设计器插件

    我无法在 Mac 上安装 qwt 设计器插件 我已经下载了 v 6 1 3 并成功完成了 qmake make 和 sudo make install 问题是 在 usr local qwt 6 1 3 lib 下 我只有文件 qwt fr
  • 使用Qt设置http get请求参数

    我正在 Qt 中开发一个基本应用程序 它使用 REST API 从 Parse com 检索数据 我浏览了一些类参考和 cURL 手册 但仍然不清楚如何设置请求参数 例如 我想对用户进行身份验证 这是 Parse 提供的curl 示例 cu
  • 纹理openGl。 C++、qt

    我试图用草纹理覆盖我的地形 由高度图制成 但它没有按预期工作 我什至无法在简单的 GL QUAD 上获取纹理 结果是多色网络 void GLWidget initializeGL glEnable GL TEXTURE 2D 在 QGLwi
  • 如何使用 QWebElement 设置 input(type="file") 的值?

    我正在尝试将照片上传到vk com https vk com using QtWebKit https qt project org doc qt 4 8 qtwebkit html模块 我面临的问题是无法正确填写input type fi
  • qmake 和 QT_INSTALL_PREFIX。如何为 Qt 库选择新位置?

    我是 qmake 的新手 我正在尝试构建一个现有的应用程序 Qt 最初安装在 usr local lib Qt 4 3 5 中 qmake query QT INSTALL PREFIX 返回该路径 我已将 Qt 库移动到另一个位置 生成的
  • Qt 的 sysroot 和前缀选项的实际示例是什么

    我正在查看可以运行的所有选项configureQt 提供的脚本 特别是 qt everywhere opensource src 5 2 0 经过大量搜索后 我确定这些东西充其量记录很少 所以我希望我能得到一些帮助 当我查看描述时prefi
  • 从 Qt 中的半透明小部件中擦除绘制区域

    我面临着必须擦除 Qt 小部件上先前绘制的区域的问题 基本思想是 用户通过单击并拖动鼠标来选择屏幕的一个区域 并在所选区域上绘制一个矩形 标题 class ClearBack public QWidget Q OBJECT public e
  • Qt 中的 QRadioButton 选中/取消选中问题

    我发现与选中 取消选中 QRadioButton 相关的问题 我用于检查 白点 和取消检查 没有白点 的图像未更新 我的问题是 我已经实现了一些 QRadioButton 第一次所有 QRadioButton 都检查为 false 因此 本

随机推荐

  • 工作十年的程序员,总结的前端面试题!

    1 常用那几种浏览器测试 有哪些内核 Layout Engine 1 浏览器 IE Chrome FireFox Safari Opera 2 内核 Trident Gecko Presto Webkit 2 说下行内元素和块级元素的区别
  • 贝叶斯网络结构学习约束的帕累托(pareto)最优

    约束 无非要考虑两件事 一是算法的结果准确率 二是算法的运行速度 约束算法的帕累托 pareto 最优就是指在保证算法准确性不降的前提下 使得算法的运行速度达到最快 就实现了帕累托最优 在已知贝叶斯网络标准结构的情况下对贝叶斯网络结构进行学
  • 人工智能之数学(概率方面)

    我们经常使用的统计机器学习算法 或者是神经网络模型中 数学作为最基础的根基 融合了高等数学中的微分学 概率 线性代数 凸优化等方面 每一个方面深入后都是有很多的益处 但是本着先实用 在进行学习的原则 所以主要是理解相关数学符号 理解统计学习
  • RocketMQ吐血总结

    RocketMQ吐血总结 架构 概念模型 最基本的概念模型与扩展后段概念模型 存储模型 RocketMQ吐血总结 User Guide RocketMQ是一款分布式消息中间件 最初是由阿里巴巴消息中间件团队研发并大规模应用于生产系统 满足线
  • 矩阵分解(1)-- 矩阵分解之LU、LDLT、Cholesky分解

    1 分类 矩阵分解 decomposition factorization 是多半将矩阵拆解为数个三角形矩阵 triangular matrix 依使用目的的不同 可分为几类 与线性方程解法相关的矩阵分解 LU分解 奇异值分解 QR分解 极
  • 使用Tmux的基本操作与后台运行命令

    文章目录 Tmux简介 Tmux安装 Tmux基本使用 Tmux后台运行程序 Tmux简介 Tmux是 终端复用器 经常看到这种说法 它是可以把一次会话中的命令记录下来的工具 会话 终端 命令 程序的关系是 终端 交互的工具 gt 会话 一
  • 初始化字典的6种方式

    查了这么多资料 我就选取几个最常见的初始化字典的方法来说明一下吧 1 最直观 最易懂的 dic1 1years 1 2years 2 3years 3 4years 4 5years 5 2 dic2 dict t 1 p 2 注意 其中等
  • Sqli-labs靶场笔记5(Less8 布尔型注入)

    Less8跟之前的Less5 Less6一样 也可以用布尔型注入来做 我们简单的测试就可以知道闭合方式也是 所以关于原理部分就不写了 有疑惑的可以直接看我前面的博客 下面直接给出具体payload 报数据库名 id 1 and substr
  • 武邑中学2021高考成绩查询,武邑中学高考成绩

    问 衡水武邑中学怎么样 答 收费2 3万 大前年中考400多分的进衡水二中的去年高考600多分 而中考400多分去武中的去年高考300分都不到 这可是有名有姓的真人的真实情况 光复习生每年就60多个班 应届考生30多个班 每年六七千人都抬不
  • 箭头函数()=>{}与function的区别

    1 箭头函数与function定义函数的写法 function function fn a b return a b arrow function var foo a b gt return a b 2 this的指向 使用function
  • uni-app开发总结分享

    目录 一 uni app介绍 二 uni app和vue的具体区别 1 组件 标签的变化 2 js 3 uniapp自带路由和请求方式 三 环境搭建 1 安装HbuilderX 2 创建uni app项目 四 项目目录结构 五 运行uni
  • 安装mysql提示3306端口已经被占用解决方案

    今天遇到的问题是这样的 之前已经安装过mysql了 一直用的好好的 但是今天开启服务时报异常 无法启动 为了省事 于是想到卸载重装 在安装的过程中发现3306已经被占用 这也是一开始服务无法启动的原因 看到有人说用fport查看端口号 于是
  • JSP学生网上选课系统设计(源代码+论文+答辩PPT)

    QQ 19966519194 摘要 随着科学技术的不断提高 计算机科学日渐成熟 其强大的功能已为人们深刻认识 它已进入人类社会的各个领域并发挥着越来越重要的作用 学生选课系统作为一种现代化的教学技术 以越来越受到人民的重视 是一个学校不可缺
  • [Unity][ShaderGraph][FlowCanvas] SetFloat 无效:通过脚本控制 shader 的动态参数时需要使用参数的引用名

    我的 shader 很简单 就是一个 tiling and offset 制作滚动效果 然后我想用一个脚本控制 speed 但是实际运行没有起效果 一开始我看的这个 然后用的 sharedmaterial https forum unity
  • Stable Diffuse AI 绘画 之 ControlNet 插件及其对应模型的下载安装

    Stable Diffuse AI 绘画 之 ControlNet 插件及其对应模型的下载安装 目录 Stable Diffuse AI 绘画 之 ControlNet 插件及其对应模型的下载安装 一 简单介绍 二 ControlNet 插
  • Swift - 将String类型的数字转换成数字类型(支持十进制、十六进制)

    https www cnblogs com Free Thinker p 7243683 html 1 十进制的字符串转成数字 Swift中 如果要把字符串转换成数字类型 比如整型 浮点型等 可以先转成NSString类型 让后再转 1 2
  • JAVA:jdbc:sqlserver 连接SQLserver实例名

    weChatjdbc driverClassName com microsoft sqlserver jdbc SQLServerDriver weChatjdbc url jdbc sqlserver 127 0 0 1 instance
  • Ubuntu服务器下安装FastDFS及nginx配置访问等问题记录

    Ubuntu服务器下安装FastDFS及nginx配置访问 下载对应包 编译环境 包解压环境配置 配置nginx模块和安装nginx来进行访问该图片 下载对应包 下载方式一 直接使用 wget 下载 如果太慢 可以去github下载 然后上
  • 基于Matlab开发的动态机器人轨迹仿真

    基于Matlab开发的动态机器人轨迹仿真 近年来 机器人技术的发展已经进入了高速发展时期 控制与仿真技术作为机器人领域中至关重要的一环 也随之发展壮大 而在动态机器人轨迹仿真方面 Matlab作为一款具备强大数学计算能力的软件 在该领域中得
  • QT实现sqlite数据库连接池

    ifndef CONNECTIONPOOL H define CONNECTIONPOOL H FileName 数据库连接池 Function 获取连接时不需要了解连接的名字 支持多线程 保证获取到的连接一定是没有被其他线程正在使用 按需