目录
前言
QT软件开发过程中,数据库是很常用的组件,方便使用特地开发数据库连接池类,包含如下特性:
- 支持同时创建多个数据库连接池
- 支持MySql、Sqlite,其他类型也很方便扩充
- 只有一个hpp文件,只需要include便可以在项目中使用
一、源代码
QConnectionPool.hpp
#pragma once
#include <QtSql>
#include <QQueue>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>
enum DB_TYPE
{
DB_SQLITE = 0,
DB_MYSQL,
};
class QConnectionPool
{
public:
QConnectionPool(int nId)
{
m_nPoolID = nId;
m_strHostName = "localhost";
m_strDatabaseName = "trial_video";
m_strUsername = "root";
m_strPassword = "123456";
m_strDatabaseType = "QMYSQL";
testOnBorrow = true;
testOnBorrowSql = "SELECT 1";
m_nPort = 3306;
maxWaitTime = 1000;
waitInterval = 200;
maxConnectionCount = 20;
}
~QConnectionPool()
{
foreach(QString connectionName, usedConnectionNames)
{
QSqlDatabase::removeDatabase(connectionName);
}
foreach(QString connectionName, unusedConnectionNames)
{
QSqlDatabase::removeDatabase(connectionName);
}
}
void release()
{
delete this;
}
void setMysqlPara(QString strUserName, QString strPassword, QString strHostName, int nPort, QString strDatabaseName)
{
m_strHostName = strHostName;
m_strUsername = strUserName;
m_strPassword = strPassword;
m_nPort = nPort;
m_strDatabaseType = "QMYSQL";
m_strDatabaseName = strDatabaseName;
m_eDbType = DB_MYSQL;
}
void setSQlitePara(QString strDatabaseName)
{
m_strDatabaseName = strDatabaseName;
m_strDatabaseType = "QSQLITE";
m_eDbType = DB_SQLITE;
}
DB_TYPE GetDBType()
{
return m_eDbType;
}
QSqlDatabase openConnection()
{
QString connectionName;
QMutexLocker locker(&mutex);
// 已创建连接数
int connectionCount = unusedConnectionNames.size() + usedConnectionNames.size();
// 如果连接已经用完,等待 waitInterval 毫秒看看是否有可用连接,最长等待 maxWaitTime 毫秒
for (int i = 0; i < maxWaitTime && unusedConnectionNames.size() == 0 && connectionCount == maxConnectionCount; i += waitInterval)
{
waitConnection.wait(&mutex, waitInterval);
// 重新计算已创建连接数
connectionCount = unusedConnectionNames.size() + usedConnectionNames.size();
}
if (unusedConnectionNames.size() > 0)
{
// 有已经回收的连接,复用它们
connectionName = unusedConnectionNames.dequeue();
}
else if (connectionCount < maxConnectionCount)
{
// 没有已经回收的连接,但是没有达到最大连接数,则创建新的连接
connectionName = QString("Connection-%1-%2").arg(m_nPoolID).arg(connectionCount + 1);
}
else
{
// 已经达到最大连接数
qDebug() << "Cannot create more connections.";
return QSqlDatabase();
}
// 创建连接
QSqlDatabase db = createConnection(connectionName);
// 有效的连接才放入 usedConnectionNames
if (db.isOpen())
{
usedConnectionNames.enqueue(connectionName);
}
return db;
}
void closeConnection(QSqlDatabase connection)
{
QString connectionName = connection.connectionName();
// 如果是我们创建的连接,从 used 里删除,放入 unused 里
if (usedConnectionNames.contains(connectionName))
{
QMutexLocker locker(&mutex);
usedConnectionNames.removeOne(connectionName);
unusedConnectionNames.enqueue(connectionName);
waitConnection.wakeOne();
}
}
private:
QSqlDatabase createConnection(const QString &connectionName)
{
// 连接已经创建过了,复用它,而不是重新创建
if (QSqlDatabase::contains(connectionName))
{
QSqlDatabase db1 = QSqlDatabase::database(connectionName);
if (testOnBorrow)
{
// 返回连接前访问数据库,如果连接断开,重新建立连接
QSqlQuery query(testOnBorrowSql, db1);
if (query.lastError().type() != QSqlError::NoError && !db1.open())
{
qDebug() << "Open datatabase error:" << db1.lastError().text();
return QSqlDatabase();
}
}
return db1;
}
// 创建一个新的连接
QSqlDatabase db = QSqlDatabase::addDatabase(m_strDatabaseType, connectionName);
if (m_strDatabaseType.compare("QSQLITE", Qt::CaseInsensitive) == 0)
{
db.setDatabaseName(m_strDatabaseName);
}
else if (m_strDatabaseType.compare("QMYSQL", Qt::CaseInsensitive) == 0)
{
db.setHostName(m_strHostName);
db.setDatabaseName(m_strDatabaseName);
db.setUserName(m_strUsername);
db.setPassword(m_strPassword);
db.setPort(m_nPort);
}
if (!db.open())
{
qDebug() << "Open datatabase error:" << db.lastError().text();
return QSqlDatabase();
}
return db;
}
QQueue<QString> usedConnectionNames; // 已使用的数据库连接名
QQueue<QString> unusedConnectionNames; // 未使用的数据库连接名
//数据库信息
QString m_strHostName;
QString m_strDatabaseName;
QString m_strUsername;
QString m_strPassword;
QString m_strDatabaseType;
int m_nPort;
bool testOnBorrow; // 取得连接的时候验证连接是否有效
QString testOnBorrowSql; // 测试访问数据库的 SQL
int maxWaitTime; // 获取连接最大等待时间
int waitInterval; // 尝试获取连接时等待间隔时间
int maxConnectionCount; // 最大连接数
QMutex mutex;
QWaitCondition waitConnection;
int m_nPoolID;
DB_TYPE m_eDbType;
};
class QConnectionPoolMuti
{
public:
QConnectionPoolMuti(void)
{}
~QConnectionPoolMuti(void)
{
QMap<int, QConnectionPool*>::iterator it = m_mapPool.begin();
while (it != m_mapPool.end())
{
it.value()->release();
it++;
}
m_mapPool.clear();
}
public:
QMap<int, QConnectionPool*> m_mapPool;
QConnectionPool* GetPool(int nId = 0)
{
QMutexLocker locker(&mutex);
QMap<int, QConnectionPool*>::iterator it = m_mapPool.find(nId);
if (it == m_mapPool.end())
{
locker.unlock();
return CreatePool(nId);
}
return it.value();
}
QConnectionPool* CreatePool(int nId)
{
QMutexLocker locker(&mutex);
QConnectionPool* pPool = new QConnectionPool(nId);
m_mapPool[nId] = pPool;
return pPool;
}
void ReleasePool(int nId)
{
QMutexLocker locker(&mutex);
QConnectionPool* pool = GetPool(nId);
if (pool == nullptr)
{
return;
}
pool->release();
QMap<int, QConnectionPool*>::iterator it = m_mapPool.find(nId);
if (it != m_mapPool.end())
{
m_mapPool.erase(it);
}
return;
}
static QConnectionPoolMuti &Instance()
{
static QConnectionPoolMuti Instance;
return Instance;
}
private:
QMutex mutex;
};
inline QConnectionPoolMuti &ConnectionPoolMuti()
{
return QConnectionPoolMuti::Instance();
}
inline QConnectionPool* ConnectionPool(int nId = 0)
{
return ConnectionPoolMuti().GetPool(nId);
}
二、使用示例
//定义连接池ID
#define DB1 0
#define DB2 1
//创建sqlite数据库连接池
ConnectionPool(DB1)->setSQlitePara("c:/test.db");
//读取数据
QSqlDatabase db1 = ConnectionPool(DB1)->openConnection();
if (!db1.isValid())
{
return false;
}
QString strSql1 = QString("select * from test_db");
QSqlQuery query1(strSql1, db1);
while (query1.next())
{
//...
}
ConnectionPool(DB1)->closeConnection(db1);
//创建mysql数据库连接池
ConnectionPool(DB2)->setMysqlPara("root", "123456", "127.0.0.1", 3306, "test_db");
//读取数据
QSqlDatabase db2 = ConnectionPool(DB2)->openConnection();
if (!db2.isValid())
{
return false;
}
QString strSql2 = QString("select * from test_db");
QSqlQuery query2(strSql2, db2);
while (query2.next())
{
//...
}
ConnectionPool(DB2)->closeConnection(db2);
总结
以上就是QT数据库连接池代码,使用起来十分简单,但真正操作过程中难免会遇到一些问题,欢迎大家评论区里留言。
关于QT使用过程中遇到的一些问题,也可以留言告诉我,后期也会继续分享一些QT开发过程中的经验总结。