#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