项目中数据库连接池总结

在个人的项目中使用到了mysql连接池与redis连接池,记录一下编码的思路和调试过程中遇到的一些问题。

1 整体实现思想

mysql与redis均使用到了连接池,因此将其从一个公有抽象类中继承出来,每个连接池实现自己的类方法

template<typename T>
class connection_pool
{
public:
    virtual void init() = 0;
    virtual T * GetConnection() = 0;		      //获取数据库连接
	virtual bool ReleaseConnection(T *conn) = 0;  //释放连接
	virtual int GetFreeConn() = 0;				  //获取连接
	virtual void DestroyPool() = 0;	

};
class mysql_connection_pool:public connection_pool<mysql_conn>
{
public:
	mysql_conn * GetConnection();				 
	bool ReleaseConnection(mysql_conn *conn); 
	int GetFreeConn();					 
	void DestroyPool();					 
	static mysql_connection_pool *GetInstance();
	void init();
	static int m_MaxConn;
private:
	mysql_connection_pool();
	~mysql_connection_pool();
	int m_CurConn;  //当前已使用的连接数
	int m_FreeConn; //当前空闲的连接数
	locker lock;
	list<mysql_conn *> connList; 
	sem reserve;

};

class redis_connection_pool:public connection_pool<redis_conn>
{
public:
    redis_conn * GetConnection();		       //获取数据库连接
	bool ReleaseConnection(redis_conn *conn);  //释放连接
	int GetFreeConn();					       //获取连接
	void DestroyPool();					       //销毁连接池
    void init();
public:
    static redis_connection_pool* GetInstance();
    static int m_MaxConn;
private:
    redis_connection_pool();
    ~redis_connection_pool();
    list<redis_conn *> connList; 
	sem reserve;
    locker lock;
	int m_CurConn; 
	int m_FreeConn; 
};

以上即派生出了mysql连接池与redis连接池,为了保证只有一个对象对声明出来,即将两个池均设计为了单例模式

mysql_connection_pool *mysql_connection_pool::GetInstance()
{
	static mysql_connection_pool connPool;
	return &connPool;
}

以上以为一个线程安全的单例模式,之所以没有上锁,C++11标准中,局部静态变量初始化具有线程安全性。
在简单实现了连接池的设计之后,还剩下一个主要的问题如果我们获取到连接之后,如果忘记及时的释放连接,会导致线程池中其他线程获取步到连接,无法处理请求,为了解决这个问题,可以利用RAII机制来帮助我们释放资源,即利用对象的生存周期来对资源进行管理,智能指针正是用这样的思想实现的,下面贴出代码:

template <typename T1, typename T2>
class connectionRAII
{
public:
	connectionRAII(T1 * &con, T2 *connPool);
	~connectionRAII();
private:
	T1 *conRAII;
	T2 *poolRAII;
};
template <typename T1, typename T2>
connectionRAII<T1, T2>::connectionRAII(T1 * &con, T2 *connPool)
{
	con = connPool->GetConnection();
	conRAII = con;
	poolRAII = connPool;
}
template <typename T1, typename T2>
connectionRAII<T1,T2>::~connectionRAII()
{
	poolRAII->ReleaseConnection(conRAII);
}

至此,两个连接池即实现了。

2 调试过程

1 mysql_real_connection 段错误

在调试过程中,发生段错误利用GDB调试定位到mysql_real_connection这个函数发生段错误,进一步跟踪发现是在初始化MYSQL句柄错误,不可以直接使用指针来进行初始化,应该使用一个局部变量初始化,如下代码:

	MYSQL  mysql_con;
	if(!mysql_init(&mysql_con))
	{
		LOG_ERROR("MySQL init Error");
		exit(1);
	}
	this->conn = mysql_real_connect(&mysql_con, addr.c_str(), user.c_str(), passwd.c_str(), db.c_str(), 3306, NULL, 0);
	if(conn == NULL)
	{
		LOG_ERROR("MySQL connect Error is %s",mysql_error(mysql_con));
		exit(1);
	}

PS:该问题一直没有想通是为什么,打算有时间的看一下相关源码,找一下具体原因

2 在创建MYSQL连接句柄时,创建了8个相同的句柄

在这里插入图片描述
如图1
对此,仍然是第一个问题中初始化的问题,将MYSQL mysql_con 改为动态对象初始化即可解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值