自动释放数据库句柄和结果集(RAII机制)

之前写了个RAII机制的数据库句柄和结果集管理,如果有同样需求的,可以参考下。支持多个句柄同时管理。句柄和结果集自动释放。

注:其中有些接口是基于之前项目的,可替换成其他对应的。


/************************************************************************/
/* DB操作的代理操作,可自动获得和释放handle和recordset                   */
/************************************************************************/
#ifndef _HWDBDELEGATERAII_20201201_
#define _HWDBDELEGATERAII_20201201_
//
// RAII机制的DB使用
#include "hwsdk/hwDBConnPool.h"
#include <typeinfo>
#include <functional>

// DBConnPoolType固定为hwDBConnPool*...
template<typename... DBConnPoolType>
class hwDBDelegateRAII final
{
#define INVALIDCONNHANDLEID (connHandleID)-1
private:
	// 定义成常量
	using DBConnPoolManagerType = std::pair<connHandleID, hwDBConnPool*>;
	const DBConnPoolManagerType m_dbConnPoolManager[sizeof...(DBConnPoolType)];
	connHandleID DefaultGetHandleFunc(unsigned int hashcode, hwDBConnPool* dbConnPool)
	{
		if (nullptr == dbConnPool)
		{
			return INVALIDCONNHANDLEID;
		}

		if (0 == hashcode)
		{
			return dbConnPool->getHandle();
		}
		else
		{
			return dbConnPool->getSaleHandle(hashcode);
		}
	}
private:
	hwDBDelegateRAII(const hwDBDelegateRAII&) = delete;
	hwDBDelegateRAII(hwDBDelegateRAII&&) = delete;
	hwDBDelegateRAII& operator =(const hwDBDelegateRAII&) = delete;
	hwDBDelegateRAII& operator =(hwDBDelegateRAII&&) = delete;
private:
	/**
	* \brief 根据nIndex对应获取DBConnPoolManagerType
	* \example dbDelegateRAII.getDBConnPoolManager() 或 dbDelegateRAII.getDBConnPoolManager<1++>()
	*/
	// !!!私有 禁止外部获取connHandleID 防止获取HandleID去自己操作
	template<int nIndex = 0>
	DBConnPoolManagerType getDBConnPoolManager() const
	{
		static_assert(nIndex >= 0 && nIndex < (sizeof...(DBConnPoolType)), "nIndex can not greater than definition");
		return m_dbConnPoolManager[nIndex];
	}

	/**
	* \brief 根据nIndex对应获取connHandleID
	* \example dbDelegateRAII.getDBConnHandleID() 或 dbDelegateRAII.getDBConnHandleID<1++>()
	*/
	// !!!私有 禁止外部获取connHandleID 防止获取HandleID去自己操作
	template<int nIndex = 0>
	connHandleID getDBConnHandleID() const
	{
		static_assert(nIndex >= 0 && nIndex < (sizeof...(DBConnPoolType)), "nIndex can not greater than definition");
		return m_dbConnPoolManager[nIndex].first;
	}
public:
	/**
	* \brief 统一采用getHandle()或getSaleHandle(hashcode)获取connHandleID
	* \param hashcode为putURL时传入的值
	* \example hwDBDelegateRAII<hwDBConnPool*> dbDelegateRAII(0, SessionServer::dbZoneConnPool);
	* \example hwDBDelegateRAII<hwDBConnPool*, hwDBConnPool*> dbDelegateRAII(1, SessionServer::dbLogConnPool, SessionServer::dbLogallConnPool);
	*/
	template<typename... ArgsFunc>
	hwDBDelegateRAII(unsigned int hashcode, DBConnPoolType... dbConnPool) :m_dbConnPoolManager({ DBConnPoolManagerType(DefaultGetHandleFunc(hashcode, dbConnPool), dbConnPool)... })
	{
	}

	/**
	* \brief 采用各自getHandle()或getSaleHandle(hashcode)获取connHandleID
	* \param hashcode为putURL时传入的值,和DBConnPoolType...对应;std::pair<hashcode, DBConnPoolType>...
	* \example hwDBDelegateRAII<hwDBConnPool*, hwDBConnPool*> dbDelegateRAII({0, SessionServer::dbZoneConnPool}, {1, SessionServer::dbLogConnPool});
	* \example hwDBDelegateRAII<hwDBConnPool*, hwDBConnPool*> dbDelegateRAII({1, SessionServer::dbLogConnPool}, {1, SessionServer::dbLogallConnPool});
	*/
	template<typename... ArgsFunc>
	hwDBDelegateRAII(std::pair<unsigned int, DBConnPoolType>... dbConnPoolPair) :m_dbConnPoolManager({ DBConnPoolManagerType(DefaultGetHandleFunc(dbConnPoolPair.first, dbConnPoolPair.second), dbConnPoolPair.second)... })
	{
	}

	/**
	* \brief DBConnPoolType...的所有采用统一的getHandleFunc获取connHandleID,如果需要不同的获取方法,那就定义多个hwDBDelegateRAII对象
	* \param getHandleFunc 采用自定义方式获取connHandleID
	* \example hwDBDelegateRAII<hwDBConnPool*> dbDelegateRAII([](hwDBConnPool* dbConnPool){return dbConnPool->getHandle(NULL, 9999);}, SessionServer::dbZoneConnPool);
	* \example hwDBDelegateRAII<hwDBConnPool*, hwDBConnPool*> dbDelegateRAII([](hwDBConnPool* dbConnPool){return dbConnPool->getSaleHandle(1, 9999);}, SessionServer::dbLogConnPool, SessionServer::dbLogallConnPool);
	*/
	template<typename... ArgsFunc>
	hwDBDelegateRAII(std::function<connHandleID(hwDBConnPool*)> getHandleFunc, DBConnPoolType... dbConnPool) :m_dbConnPoolManager({ DBConnPoolManagerType((getHandleFunc != nullptr) ? getHandleFunc(dbConnPool) : INVALIDCONNHANDLEID, dbConnPool)... })
	{
	}

	/**
	* \brief 释放所有的connHandleID
	*/
	~hwDBDelegateRAII()
	{
		for (auto dbConnPoolItem : m_dbConnPoolManager)
		{
			if (INVALIDCONNHANDLEID != dbConnPoolItem.first)
			{
				if (dbConnPoolItem.second != nullptr)
				{
					dbConnPoolItem.second->putHandle(dbConnPoolItem.first);
				}
				dbConnPoolItem.first = INVALIDCONNHANDLEID;
			}
		}
	}

	/**
	* \brief 根据nIndex对应获取hwDBConnPool*
	* \example dbDelegateRAII.getDBConnPool() 或 dbDelegateRAII.getDBConnPool<1++>()
	*/
	template<int nIndex = 0>
	hwDBConnPool* getDBConnPool() const 
	{
		static_assert(nIndex >= 0 && nIndex < (sizeof...(DBConnPoolType)), "nIndex can not greater than definition");
		return m_dbConnPoolManager[nIndex].second;
	}

	/**
	* \brief 检查传入的所有Handle有效(connHandleID和hwDBConnPool*)
	*/
	bool checkHandleAllValid() const 
	{
		int nValidCount = 0;
		for (auto dbConnPoolItem : m_dbConnPoolManager)
		{
			if (INVALIDCONNHANDLEID != dbConnPoolItem.first && nullptr != dbConnPoolItem.second)
			{
				++nValidCount;
			}
		}
		if (nValidCount == (sizeof...(DBConnPoolType)))
			return true;
		return false;
	}

	/**
	* \brief 检查nIndex对应的HandleID有效(connHandleID和hwDBConnPool*)
	* \example dbDelegateRAII.checkHandleValid() 或 dbDelegateRAII.checkHandleValid<1++>()
	*/
	template<int nIndex = 0>
	bool checkHandleValid() const 
	{
		// handleID有效且DBConnPool不空
		if ((INVALIDCONNHANDLEID != getDBConnHandleID<nIndex>()) && nullptr != getDBConnPool<nIndex>())
			return true;
		return false;
	}

	/**
	* \brief 代理处理hwDBConnPool中的函数,比直接调用少传一个connHandleID参数(如 
		int retcode = -1;
		dbDelegateRAII.DBDelegate(retcode, &hwDBConnPool::execSql, query_sql, strlen(query_sql));
	 和
		DWORD retcode = dbDelegateRAII.getDBConnPool()->exeUpdate(dbDelegateRAII.getDBConnHandleID(),"blackmarket", &column, &where);)
	* \param ReturnValue func调用后的返回值(如果返回RecordSet,需要自己管理之类的空间)
	* \param func hwDBConnPool中的处理函数,注意不能为空(如hwDBConnPool::exeInsert)
	* \param args func的参数列表
	* \return bool 代表代理执行是否成功
	*/
	/**
	* \example 使用DBDelegate方法 dbDelegateRAII.DBDelegate(returnValue, &hwDBConnPool::exeInsert, "blackmarket", &column);

	* \example 使用原始方法(从安全性考虑 此方式被禁止了) DWORD retcode = dbDelegateRAII.getDBConnPool()->exeUpdate(dbDelegateRAII.getDBConnHandleID(),"blackmarket", &column, &where);)
	*/
	template<int nIndex = 0, typename ReturnValue, typename... ArgsFunc, typename... Args>
	bool DBDelegate(ReturnValue& returnValue, ReturnValue(hwDBConnPool::*func)(connHandleID, ArgsFunc...), Args&&... args) const
	{
		if (nullptr == func || !checkHandleValid<nIndex>())
		{
			return false;
		}

		// returnValue这里会丢失掉右值引用 但也没太大关系
		returnValue = (getDBConnPool<nIndex>()->*func)(getDBConnHandleID<nIndex>(), std::forward<Args>(args)...);
		return true;
	}

	/**
	* \brief 代理处理hwDBConnPool中的函数,比直接调用少传一个connHandleID参数
	* \param handleRecordSetFunc RecordSet的回调处理函数;为nullptr则不处理查询结果
	* \param func hwDBConnPool中返回值是RecordSet*的处理函数,注意不能为空(如hwDBConnPool::exeSelect)
	* \param args func的参数列表(参数得全部传入(包括默认参数);指针不能用NULL需要使用nullptr才能正常推导类型)
	* \return bool 代表代理执行是否成功
	*/
	/**
	* \example dbDelegateRAII.DBDelegateRecordSet([&](RecordSet& recordSet) {}, &hwDBConnPool::exeSelect, "blackmarket", &column, nullptr, nullptr, 0, nullptr, nullptr);
	*/
	template<int nIndex = 0, typename... ArgsFunc, typename... Args>
	bool DBDelegateRecordSet(std::function<void(RecordSet&)> handleRecordSetFunc, RecordSet*(hwDBConnPool::*func)(connHandleID, ArgsFunc...), Args&&... args) const 
	{
		if (nullptr == func || !checkHandleValid<nIndex>())
		{
			return false;
		}
		// 获取结果集
		RecordSet* pRecordSet = (getDBConnPool<nIndex>()->*func)(getDBConnHandleID<nIndex>(), std::forward<Args>(args)...);
		if (!pRecordSet)
		{
			return false;
		}

		if (pRecordSet->empty())
		{
			delete pRecordSet;
			pRecordSet = nullptr;
			return false;
		}

		// 执行调用方的业务逻辑(pRecordSet中一定有数据)
		if (nullptr != handleRecordSetFunc)
		{
			handleRecordSetFunc(*pRecordSet);
		}

		// 释放结果集
		delete pRecordSet;
		pRecordSet = nullptr;
		return true;
	}

	template<int nIndex = 0, typename... ArgsFunc, typename... Args>
	bool CheckDBDelegateRecordSetNull(RecordSet* (hwDBConnPool::* func)(connHandleID, ArgsFunc...), Args&&... args) const
	{
		if (nullptr == func || !checkHandleValid<nIndex>())
		{
			return false;
		}
		// 获取结果集
		RecordSet* recordSet = (getDBConnPool<nIndex>()->*func)(getDBConnHandleID<nIndex>(), std::forward<Args>(args)...);
		if (!recordSet)
		{
			return true;
		}

		if (recordSet->empty())
		{
			delete recordSet;
			recordSet = nullptr;
			return true;
		}

		// 释放结果集
		delete recordSet;
		recordSet = nullptr;
		return false;
	}
};
//
#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值