当前位置: 首页 > news >正文

【Qt】 数据库连接池

Qt 数据库连接池

一、核心流程拆解(5步)
  1. 初始化连接池(init

    • 接收数据库配置(类型、IP、端口、账号密码等)及连接池参数(最大连接数、最小空闲连接数)。
    • 预先创建minIdleConnections个空闲连接,存入队列m_connections,并记录总连接数m_totalConnections
    • 标记连接池为“已初始化”(m_isInitialized = true)。
  2. 获取连接(acquireConnection

    • 若连接池未初始化,直接返回无效连接。
    • 优先从队列中取空闲连接,通过isConnectionValid验证有效性(执行SELECT 1检查连接是否存活):
      • 有效则直接返回;
      • 无效则销毁该连接(总连接数减1),继续尝试取其他连接。
    • 若队列无可用连接且总连接数未达maxConnections,调用createConnection创建新连接,总连接数加1并返回。
    • 若连接数达上限,通过QWaitCondition阻塞等待(超时退出),直到有连接被释放。
  3. 释放连接(releaseConnection

    • 若连接无效(未打开),直接销毁(总连接数减1)。
    • 若总连接数超上限或空闲连接数已达minIdleConnections,销毁该连接(总连接数减1)。
    • 否则将连接放回队列m_connections,并通过QWaitCondition::wakeOne唤醒一个等待连接的线程。
  4. 关闭所有连接(closeAllConnections

    • 遍历队列中所有空闲连接,关闭连接并通过QSqlDatabase::removeDatabase彻底移除。
    • 重置总连接数为0,标记连接池为“未初始化”。
  5. 辅助功能

    • createConnection:生成唯一连接名,创建QSqlDatabase实例并打开连接(失败则清理无效连接)。
    • isConnectionValid:通过执行SELECT 1检查连接是否存活(避免使用已断开的连接)。
二、核心知识点
  1. 线程同步机制

    • QMutex:保证连接池操作(获取/释放连接、初始化)的线程安全,避免多线程并发冲突。
    • QWaitCondition:当连接池无可用连接时,阻塞等待线程(wait);当连接被释放时,唤醒等待线程(wakeOne),实现连接的高效复用。
  2. 数据库连接管理

    • QSqlDatabase:封装数据库连接,支持多类型数据库(MySQL、SQLite、PostgreSQL),通过唯一连接名(conn_%1_%2)区分不同连接。
    • QSqlQuery:执行SELECT 1验证连接有效性,确保返回的连接可正常使用。
  3. 单例模式

    • 通过getInstance实现单例(static DbConnectionPool instance),保证全局只有一个连接池实例,统一管理所有数据库连接。
  4. 资源复用与控制

    • 预先创建空闲连接,避免频繁创建/销毁连接的开销(连接创建是重量级操作,尤其对远程数据库)。
    • 通过maxConnections限制并发连接数,防止数据库因连接过多崩溃。
三、使用示例(Qt环境)
// 1. 初始化连接池(程序启动时调用)
DbConnectionPool::getInstance().init(databaseType::QMYSQL,    // 数据库类型"127.0.0.1",             // IP3306,                    // 端口"mydb",                  // 数据库名"root",                  // 用户名"123456",                // 密码10,                      // 最大连接数3                        // 最小空闲连接数
);// 2. 获取连接并执行查询(业务逻辑中)
QSqlDatabase db = DbConnectionPool::getInstance().acquireConnection(3000); // 超时3秒
if (db.isValid() && db.isOpen()) {QSqlQuery query(db);if (query.exec("SELECT * FROM user")) {while (query.next()) {// 处理查询结果QString name = query.value("name").toString();}} else {qDebug() << "查询失败:" << query.lastError().text();}// 3. 释放连接(必须调用,否则连接池会耗尽)DbConnectionPool::getInstance().releaseConnection(db);
}// 4. 程序退出时关闭所有连接
DbConnectionPool::getInstance().closeAllConnections();
四、使用连接池的核心优点
  1. 提高性能
    避免频繁创建/销毁数据库连接(连接创建需握手、认证等耗时操作),通过复用空闲连接减少资源开销,尤其适合高并发场景。

  2. 控制资源占用
    通过maxConnections限制最大并发连接数,防止因连接过多导致数据库负载过高或崩溃。

  3. 统一连接管理
    集中处理连接的创建、验证、销毁,简化业务代码(无需手动管理连接生命周期),且便于监控连接状态(如空闲数、总连接数)。

  4. 增强稳定性
    内置连接有效性检查(isConnectionValid),自动剔除无效连接,避免使用已断开的连接导致业务失败。

  5. 线程安全
    通过QMutexQWaitCondition保证多线程环境下连接的安全获取与释放,支持多线程并发访问数据库。

总结

该连接池通过“预创建+复用+监控”连接,结合Qt的线程同步机制,实现了数据库连接的高效管理,适用于需要频繁操作数据库的Qt多线程程序,可显著提升性能并降低数据库压力。

// DbConnectionPool.h
#pragma once
#include "databasesdklib_global.h"
#include "struct_def.h"
class DbConnectionPool {
public:// 单例模式(全局唯一连接池)static DbConnectionPool& getInstance();// 禁止拷贝DbConnectionPool(const DbConnectionPool&) = delete;DbConnectionPool& operator=(const DbConnectionPool&) = delete;// 初始化连接池(需在使用前调用)void init(databaseType type, const QString& ip, int port, const QString& dbName,const QString& username, const QString& password,int maxConnections = 10, int minIdleConnections = 2);// 获取连接(若池为空且未达最大连接数,则创建新连接;否则等待)QSqlDatabase acquireConnection(int timeoutMs = 3000);// 归还连接(将连接放回池,需确保连接未关闭)void releaseConnection(QSqlDatabase db);// 关闭所有连接(程序退出时调用)void closeAllConnections();private:DbConnectionPool() = default;~DbConnectionPool() { closeAllConnections(); }// 创建新连接QSqlDatabase createConnection();// 检查连接是否有效bool isConnectionValid(const QSqlDatabase& db);private:QQueue<QSqlDatabase> m_connections; // 可用连接队列QMutex m_mutex; // 保护队列的线程安全QWaitCondition m_waitCondition; // 等待连接可用的条件变量// 数据库配置databaseType m_type;QString m_ip;int m_port;QString m_dbName;QString m_username;QString m_password;// 连接池参数int m_maxConnections = 10; // 最大连接数int m_minIdleConnections = 2; // 最小空闲连接数int m_totalConnections = 0; // 当前总连接数(包括已借出和空闲)bool m_isInitialized = false; // 是否已初始化
public:int m_count=0;
};
// DbConnectionPool.cpp
#include "DbConnectionPool.h"DbConnectionPool& DbConnectionPool::getInstance() {static DbConnectionPool instance;return instance;
}void DbConnectionPool::init(databaseType type, const QString& ip, int port, const QString& dbName,const QString& username, const QString& password,int maxConnections, int minIdleConnections) {QMutexLocker locker(&m_mutex);if (m_isInitialized) {qWarning() << "连接池已初始化,无需重复调用";return;}// 保存配置m_type = type;m_ip = ip;m_port = port;m_dbName = dbName;m_username = username;m_password = password;m_maxConnections = maxConnections;m_minIdleConnections = minIdleConnections;// 预先创建最小空闲连接for (int i = 0; i < m_minIdleConnections; ++i) {QSqlDatabase db = createConnection();if (db.isOpen()) {m_connections.enqueue(db);m_totalConnections++;}}m_isInitialized = true;
}QSqlDatabase DbConnectionPool::acquireConnection(int timeoutMs) {QMutexLocker locker(&m_mutex);if (!m_isInitialized) {qCritical() << "连接池未初始化,请先调用init()";return QSqlDatabase();}// 循环等待可用连接(超时退出)while (true) {// 1. 检查队列中是否有可用连接if (!m_connections.isEmpty()) {QSqlDatabase db = m_connections.dequeue();// 验证连接有效性(避免连接已断开)if (isConnectionValid(db)) {return db;}else {// 连接无效,销毁并减少总连接数m_totalConnections--;continue;}}// 2. 若未达最大连接数,创建新连接if (m_totalConnections < m_maxConnections) {QSqlDatabase db = createConnection();if (db.isOpen()) {m_totalConnections++;m_count++;return db;}else {qWarning() << "创建新连接失败,将重试";continue;}}// 3. 无可用连接且已达最大连接数,等待超时if (!m_waitCondition.wait(&m_mutex, timeoutMs)) {qWarning() << "获取连接超时(" << timeoutMs << "ms),当前总连接数:" << m_totalConnections;return QSqlDatabase();}}
}void DbConnectionPool::releaseConnection(QSqlDatabase db) {if (!db.isValid()) {qWarning() << "归还无效连接,忽略";return;}QMutexLocker locker(&m_mutex);// 若连接已关闭,直接销毁if (!db.isOpen()) {m_totalConnections--;m_count--;return;}// 检查是否需要销毁(若总连接数超过最大,且空闲连接数超过最小)if (m_totalConnections > m_maxConnections || m_connections.size() >= m_minIdleConnections) {m_totalConnections--;m_count--;return;}// 否则放回队列m_connections.enqueue(db);m_waitCondition.wakeOne(); // 唤醒一个等待连接的线程
}void DbConnectionPool::closeAllConnections() {QMutexLocker locker(&m_mutex);while (!m_connections.isEmpty()) {QSqlDatabase db = m_connections.dequeue();if (db.isOpen()) {db.close();}QString connName = db.connectionName();QSqlDatabase::removeDatabase(connName); // 彻底移除连接}m_totalConnections = 0;m_isInitialized = false;
}QSqlDatabase DbConnectionPool::createConnection() {// 生成唯一连接名(避免冲突)QString connName = QString("conn_%1_%2").arg(int(QThread::currentThreadId())).arg(qrand());// 根据数据库类型创建连接QString driver;if (m_type == databaseType::QMYSQL) {driver = "QMYSQL";}else if (m_type == databaseType::QSQLITE) {driver = "QSQLITE";}else if (m_type == databaseType::QPSQL) {driver = "QPSQL";}else {qCritical() << "不支持的数据库类型";return QSqlDatabase();}QSqlDatabase db = QSqlDatabase::addDatabase(driver, connName);db.setHostName(m_ip);db.setPort(m_port);db.setDatabaseName(m_dbName);db.setUserName(m_username);db.setPassword(m_password);// 打开连接if (!db.open()) {qWarning() << "创建连接失败:" << db.lastError().text() << "(连接名:" << connName << ")";QSqlDatabase::removeDatabase(connName); // 清理失败的连接return QSqlDatabase();}return db;
}bool DbConnectionPool::isConnectionValid(const QSqlDatabase& db) {if (!db.isOpen()) {return false;}// 执行简单查询验证连接(如MySQL可用"SELECT 1",SQLite可用"SELECT 1")QSqlQuery query(db);return query.exec("SELECT 1");
}
http://www.dtcms.com/a/338887.html

相关文章:

  • B站 韩顺平 笔记 (Day 23)
  • LG P3710 方方方的数据结构 Solution
  • 【Qt开发】常用控件(五)
  • DzzOffice版权信息修改教程
  • 遥感amp;机器学习入门实战教程 | Sklearn 案例③:PCA + SVM / 随机森林 对比与调参
  • CSDN 创始人蒋涛:以开源驱动技术创新,拥抱黄金十年
  • LeetCode100-560和为K的子数组
  • 开源 C++ QT Widget 开发(二)基本控件应用
  • leetcode_ 76 最小覆盖子串
  • 决策树(续)
  • 大数据技术栈 —— Redis与Kafka
  • 字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
  • 磨砂玻璃登录页面使用教程 v0.1.1
  • 【Linux仓库】进程创建与进程终止【进程·柒】
  • 通过C#上位机串口写入和读取浮点数到stm32的片内flash实战4(通过串口下发AD9833设置值并在上位机显示波形曲线)
  • 基于单片机智能点滴输液系统
  • 元素的width和offsetWidth有什么区别
  • java八股文-中间件-参考回答
  • Win11家庭版docker安装MaxKB
  • 【论文阅读】DETR3D: 3D Object Detection from Multi-view Images via 3D-to-2D Queries
  • 边缘智能体:Go编译在医疗IoT设备端运行轻量AI模型(中)
  • 【HTML】3D动态凯旋门
  • 【SpringBoot】15 核心功能 - Web开发原理 - 请求处理 - 常用请求参数注解
  • 【SpringBoot】Dubbo、Zookeeper
  • 【完整源码+数据集+部署教程】鳄梨表面缺陷检测图像分割系统源码和数据集:改进yolo11-MLCA
  • C语言第九章字符函数和字符串函数
  • Go语言快速入门指南(面向Java工程师)
  • 基于SpringBoot+Vue的养老院管理系统的设计与实现 智能养老系统 养老架构管理 养老小程序
  • 外网-内网渗透测试(文件上传漏洞利用)
  • MySQL事务篇-事务概念、并发事务问题、隔离级别