QT数据库连接池

目录

前言

一、源代码

二、使用示例

总结



前言

QT软件开发过程中,数据库是很常用的组件,方便使用特地开发数据库连接池类,包含如下特性:

  1. 支持同时创建多个数据库连接池
  2. 支持MySql、Sqlite,其他类型也很方便扩充
  3. 只有一个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开发过程中的经验总结。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值