news 2026/4/16 18:11:37

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 22:13:57

1小时搞定恒流源原型:快马平台实战

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 快速开发一个数控恒流源原型&#xff0c;通过电位器调节输出电流(0-500mA)&#xff0c;使用Arduino进行简单控制。要求&#xff1a;1) 提供完整电路图 2) Arduino示例代码 3) 关键元…

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

比console.log快10倍:专业调试React无限循环的技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个React调试工具面板&#xff0c;专门用于检测无限循环。包含渲染计数器、依赖关系可视化图表和性能分析功能。提供常见无限循环模式的快速检测模板。点击项目生成按钮&#…

作者头像 李华
网站建设 2026/4/16 9:17:31

Flutter 基于Firebase的鉴权功能集成

Firebase提供了一套SDK用于抹平不用平台鉴权的差异性&#xff0c;为了方便使用&#xff0c;将基于firebase_auth、google_sign_in、sign_in_with_apple的依赖封装一套登录统一的功能集成。鉴权后将会获取idToken&#xff0c;该数据需要传给服务器进行校验。步骤&#xff1a;1.定…

作者头像 李华
网站建设 2026/4/16 9:19:06

21、深入理解与操作SELinux策略

深入理解与操作SELinux策略 1. 利用sepolicy generate创建应用策略 对于应用程序而言, sepolicy generate 命令需要将主命令作为参数传入,以此生成一个简单的文件上下文( .fc )文件。此外, sepolicy generate 还支持以下与应用相关的模板: - --application :…

作者头像 李华
网站建设 2026/4/16 9:20:06

22、SELinux策略分析方法详解

SELinux策略分析方法详解 1. 初步角色分析 在SELinux策略分析中,可使用 sesearch 工具进行初步的角色分析。 - --role_allow 选项:用于显示允许的角色。例如,执行以下命令: $ sesearch --role_allow -s webadm_r allow webadm_r system_r;此命令显示 webadm_r 角…

作者头像 李华
网站建设 2026/4/16 7:45:03

Yaak桌面API客户端终极命令行指南:从入门到精通

Yaak桌面API客户端终极命令行指南&#xff1a;从入门到精通 【免费下载链接】yaak The most intuitive desktop API client. Organize and execute REST, GraphQL, WebSockets, Server Sent Events, and gRPC &#x1f9ac; 项目地址: https://gitcode.com/GitHub_Trending/y…

作者头像 李华