news 2026/4/18 4:02:12

sqlite数据库连接池

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
sqlite数据库连接池

Qt 实现 SQLite 连接池(线程安全版)

SQLite 本身支持多线程,但单个连接不能被多线程同时使用,因此连接池的核心是:管理一组独立的数据库连接,为每个线程分配 / 复用连接,保证线程安全,避免频繁创建 / 销毁连接的性能损耗

以下是完整的连接池实现,包含「单例模式、线程安全、连接有效性检查、最大连接数限制」核心特性:

1. 头文件(SqliteConnectionPool.h)

cpp

运行

#ifndef SQLITECONNECTIONPOOL_H #define SQLITECONNECTIONPOOL_H #include <QSqlDatabase> #include <QStack> #include <QMutex> #include <QString> #include <QWaitCondition> // SQLite 连接池(单例模式 + 线程安全) class SqliteConnectionPool { public: // 获取单例实例(C++11 线程安全的局部静态变量) static SqliteConnectionPool& getInstance(); // 获取数据库连接(若空闲连接不足则创建新连接,超出最大数则等待) QSqlDatabase getConnection(); // 归还数据库连接到连接池 void releaseConnection(const QSqlDatabase& db); // 设置连接池配置 void setConfig(const QString& dbPath, int maxConn = 10); // 释放所有连接(析构时自动调用) void releaseAllConnections(); private: // 私有构造/析构,禁止拷贝/赋值(单例约束) SqliteConnectionPool(); ~SqliteConnectionPool(); SqliteConnectionPool(const SqliteConnectionPool&) = delete; SqliteConnectionPool& operator=(const SqliteConnectionPool&) = delete; // 检查连接是否有效(执行简单 SQL 验证) bool isConnectionValid(const QSqlDatabase& db); // 创建新的数据库连接 QSqlDatabase createNewConnection(); private: QMutex m_mutex; // 线程安全锁 QWaitCondition m_cond; // 等待条件(无空闲连接时阻塞) QStack<QString> m_freeConnNames; // 空闲连接名称栈(QSqlDatabase 按名称管理) QString m_dbPath; // SQLite 数据库文件路径 int m_maxConn = 10; // 最大连接数(默认10) int m_curConn = 0; // 当前已创建的连接数 const QString m_connPrefix = "SqliteConn_"; // 连接名称前缀(保证唯一性) }; #endif // SQLITECONNECTIONPOOL_H
2. 源文件(SqliteConnectionPool.cpp)

cpp

运行

#include "SqliteConnectionPool.h" #include <QSqlQuery> #include <QDebug> #include <QThread> // 单例实例获取 SqliteConnectionPool& SqliteConnectionPool::getInstance() { static SqliteConnectionPool instance; return instance; } // 构造函数(私有) SqliteConnectionPool::SqliteConnectionPool() { // 注册 SQLite 驱动(Qt 5+ 自动注册,此处兼容低版本) qRegisterMetaType<QSqlDatabase>("QSqlDatabase"); } // 析构函数(私有) SqliteConnectionPool::~SqliteConnectionPool() { releaseAllConnections(); } // 设置连接池配置(数据库路径 + 最大连接数) void SqliteConnectionPool::setConfig(const QString& dbPath, int maxConn) { QMutexLocker locker(&m_mutex); m_dbPath = dbPath; m_maxConn = qMax(1, maxConn); // 最大连接数至少为1 } // 获取数据库连接 QSqlDatabase SqliteConnectionPool::getConnection() { QMutexLocker locker(&m_mutex); // 步骤1:优先使用空闲连接 while (m_freeConnNames.isEmpty()) { // 空闲连接为空时,判断是否可创建新连接 if (m_curConn < m_maxConn) { // 创建新连接 createNewConnection(); } else { // 超出最大连接数,等待其他线程归还连接(超时30秒) if (!m_cond.wait(&m_mutex, 30000)) { qWarning() << "获取SQLite连接超时(30秒),当前连接数已达上限:" << m_maxConn; return QSqlDatabase(); // 返回无效连接 } } } // 步骤2:取出空闲连接并验证有效性 QString connName = m_freeConnNames.pop(); QSqlDatabase db = QSqlDatabase::database(connName, false); // false:不自动打开 // 连接失效则重建 if (!isConnectionValid(db)) { qDebug() << "连接失效,重建连接:" << connName; db = createNewConnection(); } return db; } // 归还连接到池 void SqliteConnectionPool::releaseConnection(const QSqlDatabase& db) { if (!db.isValid()) return; QMutexLocker locker(&m_mutex); QString connName = db.connectionName(); // 确保连接未被重复归还 if (!m_freeConnNames.contains(connName)) { m_freeConnNames.push(connName); m_cond.wakeOne(); // 唤醒等待连接的线程 qDebug() << "归还连接:" << connName << ",当前空闲连接数:" << m_freeConnNames.size(); } } // 释放所有连接 void SqliteConnectionPool::releaseAllConnections() { QMutexLocker locker(&m_mutex); while (!m_freeConnNames.isEmpty()) { QString connName = m_freeConnNames.pop(); QSqlDatabase::removeDatabase(connName); m_curConn--; } qDebug() << "已释放所有SQLite连接,总计:" << (m_maxConn - m_curConn); } // 检查连接有效性 bool SqliteConnectionPool::isConnectionValid(const QSqlDatabase& db) { if (!db.isOpen()) return false; // 执行简单SQL验证连接(SQLite 通用) QSqlQuery query(db); return query.exec("SELECT 1"); } // 创建新连接 QSqlDatabase SqliteConnectionPool::createNewConnection() { // 生成唯一连接名称(前缀 + 当前连接数 + 线程ID,避免冲突) QString connName = m_connPrefix + QString::number(m_curConn) + "_" + QString::number((qlonglong)QThread::currentThreadId()); // 创建SQLite连接 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connName); db.setDatabaseName(m_dbPath); // SQLite 优化参数(可选,根据业务调整) db.setConnectOptions( "QSQLITE_OPEN_URI=1;" // 启用URI模式 "QSQLITE_ENABLE_SHARED_CACHE=1;" // 共享缓存(多连接时减少内存占用) "QSQLITE_BUSY_TIMEOUT=5000" // 忙时等待5秒(避免锁冲突) ); // 打开连接 if (db.open()) { m_curConn++; qDebug() << "创建新连接成功:" << connName << ",当前总连接数:" << m_curConn; } else { qCritical() << "创建SQLite连接失败:" << db.lastError().text(); QSqlDatabase::removeDatabase(connName); // 清理无效连接 } return db; }
3. 使用示例(多线程场景)

cpp

运行

#include <QCoreApplication> #include <QThread> #include <QSqlQuery> #include <QDebug> #include "SqliteConnectionPool.h" // 工作线程:执行SQL操作 class SqlWorker : public QThread { protected: void run() override { // 1. 获取连接 QSqlDatabase db = SqliteConnectionPool::getInstance().getConnection(); if (!db.isValid() || !db.open()) { qWarning() << "线程" << QThread::currentThreadId() << "获取连接失败:" << db.lastError().text(); return; } // 2. 执行SQL(示例:创建表 + 插入数据) QSqlQuery query(db); // 创建表(仅第一次执行有效) if (!query.exec("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT)")) { qWarning() << "创建表失败:" << query.lastError().text(); } // 插入数据 query.prepare("INSERT INTO test (name) VALUES (:name)"); query.bindValue(":name", "Thread_" + QString::number((qlonglong)QThread::currentThreadId())); if (query.exec()) { qDebug() << "线程" << QThread::currentThreadId() << "插入数据成功,ID:" << query.lastInsertId().toInt(); } else { qWarning() << "插入数据失败:" << query.lastError().text(); } // 3. 归还连接 SqliteConnectionPool::getInstance().releaseConnection(db); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 初始化连接池 SqliteConnectionPool& pool = SqliteConnectionPool::getInstance(); pool.setConfig("./test.db", 5); // 数据库路径 + 最大5个连接 // 创建10个工作线程(测试连接池复用) QList<SqlWorker*> workers; for (int i = 0; i < 10; i++) { SqlWorker* worker = new SqlWorker; workers.append(worker); worker->start(); } // 等待所有线程结束 for (SqlWorker* worker : workers) { worker->wait(); delete worker; } return a.exec(); }

核心特性说明

  1. 线程安全

    • 使用QMutex保证连接池的读写互斥;
    • 使用QWaitCondition实现「无空闲连接时的阻塞等待」,避免频繁创建连接。
  2. 连接有效性

    • 获取连接时执行SELECT 1验证连接是否可用,失效则自动重建。
  3. SQLite 优化参数

    • QSQLITE_BUSY_TIMEOUT=5000:遇到数据库锁时等待 5 秒,避免直接报错;
    • QSQLITE_ENABLE_SHARED_CACHE:多连接共享缓存,减少内存占用。
  4. 连接名称唯一性

    • 连接名称 = 前缀 + 连接数 + 线程 ID,避免QSqlDatabase名称冲突。

注意事项

  1. 连接必须归还:使用完连接后必须调用releaseConnection,否则会导致连接池耗尽。
  2. 避免长连接占用:业务逻辑应尽快释放连接,不要长时间持有。
  3. 线程内复用连接:同一个线程多次操作数据库时,建议复用同一个连接(无需每次都获取 / 归还)。
  4. 数据库文件权限:确保程序对 SQLite 数据库文件所在目录有读写权限。
  5. 最大连接数设置:SQLite 单文件数据库的连接数不宜过大(建议 5~20),过多连接会增加锁竞争。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 18:26:12

如何快速掌握ag-ui:构建智能代理应用的终极指南

如何快速掌握ag-ui&#xff1a;构建智能代理应用的终极指南 【免费下载链接】ag-ui 项目地址: https://gitcode.com/gh_mirrors/agu/ag-ui 你是否曾经想要开发一个能够与用户智能交互的AI应用&#xff0c;却被复杂的通信协议和状态管理困扰&#xff1f;ag-ui作为一款革…

作者头像 李华
网站建设 2026/4/16 15:01:05

Android系统Boot镜像深度定制与Root权限获取实战指南

Android系统Boot镜像深度定制与Root权限获取实战指南 【免费下载链接】Boot.img修补工具-MagiskPatcher 本仓库提供了一个名为“Boot.img 修补工具 - Magisk Patcher”的资源文件。该工具主要用于修补有锁的BOOT镜像文件&#xff0c;帮助用户在需要的情况下对Boot.img进行必要的…

作者头像 李华
网站建设 2026/4/18 0:44:43

如何用AI检测和修复React无限循环问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个React应用&#xff0c;展示一个常见的无限循环场景&#xff08;如useEffect依赖未正确设置&#xff09;。使用AI分析代码&#xff0c;自动检测潜在无限循环&#xff0c;并生…

作者头像 李华
网站建设 2026/4/17 18:28:32

30亿参数掀起企业AI革命:IBM Granite 4.0如何重塑部署范式

导语 【免费下载链接】granite-4.0-h-small-base 项目地址: https://ai.gitcode.com/hf_mirrors/unsloth/granite-4.0-h-small-base 2025年企业AI部署正面临严峻的资源挑战——传统13B参数模型的FP16部署平均需要24GB显存&#xff0c;相当于4台消费级GPU的内存总和&…

作者头像 李华
网站建设 2026/4/18 0:56:13

PaddleOCR 终极指南:从零开始掌握多语言文字识别技术

想要快速识别图片中的文字吗&#xff1f;PaddleOCR作为一款强大的开源OCR工具包&#xff0c;支持80多种语言识别&#xff0c;提供从数据标注到模型部署的全流程解决方案。无论你是开发者、研究者还是企业用户&#xff0c;这个工具都能满足你的文字识别需求。 【免费下载链接】P…

作者头像 李华
网站建设 2026/4/15 12:37:36

用substring_index快速构建日志分析原型系统

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个简易的日志分析工具原型&#xff0c;使用substring_index函数从标准日志格式中提取关键信息。日志格式示例&#xff1a;[2023-05-15 14:30:45] ERROR module.file: Error m…

作者头像 李华