tinyWebServer 学习笔记——五、数据库连接池

文章目录

  • 一、基础知识
  • 二、代码解析
    • 1. 单例模式创建
    • 2. 连接池初始化
    • 3. 获取和释放连接
    • 4. 销毁线程池
    • 5. RAII 机制释放数据库连接
  • 参考文献

一、基础知识

  • 数据库连接池:池是一组资源的集合,这组资源在服务器启动之初就被创建并初始化。数据库连接池就是专门处理数据库连接的资源,当客户发起请求时,就从池中获取资源;完成任务后,就将其放回资源池。整个过程无需使用系统调用动态分配或释放资源。
  • 数据库访问流程:先系统创建数据库连接,完成数据库操作,然后断开数据库连接;

二、代码解析

1. 单例模式创建

class connection_pool
{
public:
	// 局部静态变量单例模式
	MYSQL *GetConnection();
	// 释放连接
	bool ReleaseConnection(MYSQL *conn);
	// 获取连接
	int GetFreeConn();
	// 销毁所有连接
	void DestroyPool();

	// 单例模式
	static connection_pool *GetInstance();
	// 初始化
	void init(string url, string User, string PassWord, string DataBaseName, int Port, int MaxConn, int close_log);

private:
	// 构造函数
	connection_pool();
	// 析构函数
	~connection_pool();

	int m_MaxConn;			// 最大连接数
	int m_CurConn;			// 当前已使用的连接数
	int m_FreeConn;			// 当前空闲的连接数
	locker lock;			// 互斥锁
	list<MYSQL *> connList; // 连接池
	sem reserve;			// 信号量

public:
	string m_url;		   // 主机地址
	string m_Port;		   // 数据库端口号
	string m_User;		   // 登录数据库用户名
	string m_PassWord;	   // 登录数据库密码
	string m_DatabaseName; // 使用数据库名
	int m_close_log;	   // 日志开关
};

2. 连接池初始化

// 构造函数,初始化当前已使用连接数和空闲连接数
connection_pool::connection_pool()
{
	m_CurConn = 0;
	m_FreeConn = 0;
}

// 构造初始化
void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, int MaxConn, int close_log)
{
	// 初始化数据库信息
	m_url = url;			 // 主机地址
	m_Port = Port;			 // 数据库端
	m_User = User;			 // 登录数据
	m_PassWord = PassWord;	 // 登录数据
	m_DatabaseName = DBName; // 使用数据
	m_close_log = close_log; // 日志开关

	// 创建MaxConn条数据库连接
	for (int i = 0; i < MaxConn; i++)
	{
		MYSQL *con = NULL;
		con = mysql_init(con);

		if (con == NULL)
		{
			LOG_ERROR("MySQL Error");
			exit(1);
		}
		// 连接数据库
		con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);

		if (con == NULL)
		{
			LOG_ERROR("MySQL Error");
			exit(1);
		}
		// 更新连接池和空闲连接数量
		connList.push_back(con);
		++m_FreeConn;
	}
	// 将信号量初始化为最大连接次数
	reserve = sem(m_FreeConn);

	m_MaxConn = m_FreeConn;
}

// RAII机制销毁连接池
connectionRAII::~connectionRAII()
{
	poolRAII->ReleaseConnection(conRAII);
}

3. 获取和释放连接

// 当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{
	MYSQL *con = NULL;
	// 无可用连接
	if (0 == connList.size())
		return NULL;
	// P操作
	reserve.wait();
	// 加锁
	lock.lock();
	// 取连接池第一个连接
	con = connList.front();
	// 删除连接池第一个连接
	connList.pop_front();
	// 更新空闲连接个数和已连接数,未使用
	--m_FreeConn;
	++m_CurConn;
	// 解锁
	lock.unlock();
	return con;
}

// 释放当前使用的连接
bool connection_pool::ReleaseConnection(MYSQL *con)
{
	if (NULL == con)
		return false;

	lock.lock();
	// 更新连接池
	connList.push_back(con);
	++m_FreeConn;
	--m_CurConn;

	lock.unlock();
	// V操作
	reserve.post();
	return true;
}

4. 销毁线程池

// 销毁数据库连接池
void connection_pool::DestroyPool()
{

	lock.lock();
	if (connList.size() > 0)
	{
		// 逐个连接进行关闭
		list<MYSQL *>::iterator it;
		for (it = connList.begin(); it != connList.end(); ++it)
		{
			MYSQL *con = *it;
			mysql_close(con);
		}
		m_CurConn = 0;
		m_FreeConn = 0;

		// 清空list
		connList.clear();
	}

	lock.unlock();
}

5. RAII 机制释放数据库连接

// 资源获取即初始化的连接
class connectionRAII
{
public:
	// 双指针对MYSQL *con修改
	connectionRAII(MYSQL **con, connection_pool *connPool);
	~connectionRAII();

private:
	MYSQL *conRAII;
	connection_pool *poolRAII;
};

// RAII机制取一个可用连接
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool)
{
	// 取一个可用连接
	*SQL = connPool->GetConnection();

	conRAII = *SQL;		 // 记录分配的可用连接
	poolRAII = connPool; // 记录对象
}

// RAII机制销毁连接池
connectionRAII::~connectionRAII()
{
	poolRAII->ReleaseConnection(conRAII);
}

参考文献

[1] 最新版Web服务器项目详解 - 11 数据库连接池

你可能感兴趣的:(计算机网络,数据库,学习,笔记)