11 数据库连接池

11 数据库连接池

基础知识

什么是数据库连接池

池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化。池是资源的容器,本质上是对资源的复用。

连接池中的资源为一组数据库连接,由程序动态地对池中地连接进行使用,释放。

当系统开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中获取,无需动态分配;当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源。

数据库访问的一般流程是什么?

当系统需要访问数据库时,先系统创建数据库连接,完成数据库操作,然后系统断开数据库连接。

为什么创建连接池?

从一般流程中可以看出,若系统需要频繁访问数据库,则需要频繁创建和断开数据库连接,而创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。

在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,更加安全可靠。

整体概述

池可以看作资源的容器,所以多种实现方法,比如数组、链表、队列等。这里,使用单例模式和链表创建数据库连接池,实现对数据库连接资源的复用。

项目中的数据库模块分为两部分,其一是数据库连接池的定义,其二是利用连接池完成登录和注册的校验功能。具体的,工作线程从数据库连接池取得一个连接,访问数据库中的数据,访问完毕后将连接交还连接池。

本文内容

介绍数据库连接池的定义,涉及到单例模式创建、连接池代码实现、RAII机制释放数据库连接。
单例模式创建 ,结合代码描述连接池的单例实现。
连接池代码实现 ,结合代码对连接池的外部访问接口进行详解。
RAII机制释放数据库连接,描述连接释放的封装逻辑。

单例模式创建

使用局部静态变量懒汉模式创建连接池。

cpp 复制代码
class connection_pool
{
public:
	//局部静态变量单例模式
	static connection_pool *GetInstance();

private:
	connection_pool();
	~connection_pool();
};

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

连接池代码实现

连接池的功能主要有:初始化,获取连接,释放连接,销毁连接池。

初始化

销毁连接池没有直接被外部调用,而是通过RAII机制来完成自动释放;使用信号量实现多线程争夺连接的同步机制,将信号量初始化为数据库的连接总数。

cpp 复制代码
connection_pool::connection_pool()
{
	this->CurConn=0;
	this->FreeConn=0;
}

//RAII机制销毁连接池
connection_pool::~connection_pool()
{
	DestoryPool();
}

//构造初始化
void connection_pool::init(string url,string User,string PassWord,string DBName,int Port,unsigned int MaxConn)
{
	//初始化数据库信息
	this->url=url;
	this->Port=Port;
	this->User=User;
	this->PassWord=PassWord;
	this->DatabaseName=DBName;

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

		if(conn=NULL)
		{
			cout<<"Error:"<<mysql_error(con);
			exit(1);
		}
		con=mysql_real_connect(con,url.c_str(),User.c_str(),PassWord.c_str(),DBName.c_str(),Port,NULL,0);

		if(conn=NULL)
		{
			cout<<"Error:"<<mysql_error(conn);
			exit(1);
		}

		//更新连接池和空闲连接数据
		connList.push_back(con);
		++FreeConn;
	}

	//将信号量初始化为最大连接次数
	resverse=sem(FreeConn);

	this->MaxConn=FreeConn;
}

获取、释放连接

当线程数量大于数据库连接数量时,使用信号量进行同步,每次取出连接,信号量原子减1,释放连接原子加1,若连接池内没有连接了,则阻塞等待。

多线程操作连接池,会造成竞争,使用互斥锁完成同步,具体的同步机制均使用lock.h中封装好的类。

cpp 复制代码
//当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{
	MYSQL *con=NULL;

	if(0==connList.size())
		return NULL;

	//取出连接,信号量原子减1,为0则等待
	reserver.wait();

	lock.lock();

	con=connList.front();
	connList.pop_front();

	--FreeConn;
	++CurConn;

	lock.unlock();
	return con;
}

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

	lock.lock();

	connList.push_back(con);
	++FreeConn;
	--CurConn;

	lock.unlock();
	
	//释放连接原子加1
	reserve.post();
	return true;
}

销毁连接池

通过迭代器遍历连接池链表,关闭对应数据库连接,清空链表并重置空闲连接和现有连接数量

cpp 复制代码
//销毁数据库连接池
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);
		}
		CurConn=0;
		FreeConn=0;
	
		//清空list
		connList.clear();

		lock.unlock();
	}

	lock.unlock();
}

RAII机制释放数据库连接

将数据库连接的获取与释放通过RAII机制封装,避免手动释放

定义

在获取连接时,通过有参构造对传入参数进行修改。数据库连接本身是指针类型,所以参数需要通过双指针才能对其进行修改。

cpp 复制代码
class connectionRAII{
public:
	//双指针对MYSQL *con修改
	connectionRAII(MYSQL **conn,connection_pool *connPool);
	~connectionRAII();

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

实现

不直接调用获取和释放连接的接口,将其封装起来,通过RAII机制进行获取和释放。

cpp 复制代码
connectionRAII::connectionRAII(MYSQL **SQL,connection_pool *connPool){
	*SQL=connPool->GetConnection();

	conRAII=*SQL;
	pollRAII=connPool;
}

connectionRAII::~connectionRAII(){
	poolRAII->ReleaseConnection(conRAII);
}
相关推荐
睡觉的时候不会困5 小时前
Redis 主从复制详解:原理、配置与主从切换实战
数据库·redis·bootstrap
程序员的世界你不懂7 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
自学也学好编程7 小时前
【数据库】Redis详解:内存数据库与缓存之王
数据库·redis
JAVA不会写8 小时前
在Mybatis plus中如何使用自定义Sql
数据库·sql
IT 小阿姨(数据库)8 小时前
PgSQL监控死元组和自动清理状态的SQL语句执行报错ERROR: division by zero原因分析和解决方法
linux·运维·数据库·sql·postgresql·centos
ChinaRainbowSea8 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
小马学嵌入式~9 小时前
嵌入式 SQLite 数据库开发笔记
linux·c语言·数据库·笔记·sql·学习·sqlite
Java小白程序员10 小时前
MyBatis基础到高级实践:全方位指南(中)
数据库·mybatis
Monly2110 小时前
人大金仓:merge sql error, dbType null, druid-1.2.20
数据库·sql
不宕机的小马达10 小时前
【Mysql|第一篇】Mysql的安装与卸载、Navicat工具的使用
数据库·mysql