之前写了个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