【TinyWebServer】11数据库连接池

news/发布时间2024/5/18 17:56:08

基础知识

什么是数据库连接池?

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

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

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

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

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

为什么要创建连接池?

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

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

整体概述

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

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

本文内容

本篇将介绍数据库连接池的定义,具体的涉及到单例模式创建、连接池代码实现、RAII机制释放数据库连接。

单例模式创建 ,结合代码描述连接池的单例实现。

连接池代码实现 ,结合代码对连接池的外部访问接口进行详解。

RAII机制释放数据库连接 ,描述连接释放的封装逻辑。

单例模式创建

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

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机制来完成自动释放;使用信号量实现多线程争夺连接的同步机制,这里将信号量初始化为数据库的连接总数。


connection_pool::connection_pool()
{this->CurConn = 0;this->FreeConn = 0;
}//RAII机制销毁连接池
connection_pool::~connection_pool()
{DestroyPool();
}//构造初始化
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 (con == 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 (con == NULL){cout << "Error: " << mysql_error(con);exit(1);}//更新连接池和空闲连接数量connList.push_back(con);++FreeConn;}//将信号量初始化为最大连接次数reserve = sem(FreeConn);this->MaxConn = FreeConn;
}

获取、释放连接

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

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

//当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{MYSQL *con = NULL;if (0 == connList.size())return NULL;//取出连接,信号量原子减1,为0则等待reserve.wait();lock.lock();con = connList.front();connList.pop_front();//这里的两个变量,并没有用到,非常鸡肋...--FreeConn;++CurConn;lock.unlock();return con;
}//释放当前使用的连接
bool connection_pool::ReleaseConnection(MYSQL *con)
{if (NULL == con)return false;lock.lock();connList.push_back(con);++FreeConn;--CurConn;lock.unlock();//释放连接原子加1reserve.post();return true;
}

销毁连接池

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

//销毁数据库连接池
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;//清空listconnList.clear();lock.unlock();}lock.unlock();
}

RAII机制释放数据库连接

将数据库连接的获取与释放通过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;
}connectionRAII::~connectionRAII(){poolRAII->ReleaseConnection(conRAII);
}

转载文章:

最新版Web服务器项目详解 - 11 数据库连接池 (qq.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/75713262.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

9.25闲话

今天还是很摆。 上午模拟赛。T1 结论题,秒了。T2 haosen 给初中组讲过,忘了。T3 不知道什么题,打了 55pts 暴力跑路。T4 一眼不可做,跑路。 最终得分:\(100+10+55+5=170\),rk3。神包峰学长太深了😍😍😍 haosen 讲过一遍 T2,但是当时没听懂😅😅😅。今天神包峰…

金蝶云星空自定义WebApi

1、创建项目,命名规范:开发商.K3.SCM.WebApi.ServicesStub2、添加引用 using Kingdee.BOS.ServiceFacade.KDServiceFx; using Kingdee.BOS.WebApi.ServicesStub;3、新建类,继承webapi业务抽象服务AbstractWebApiBusinessService。/// <summary>/// 根据客户名称获取客…

AnsibleFATE部署过程

前言 基本上按照官方文档就行了,先做before deploy,再做three side guide.md。以下是可能出现的问题 这个AnsibleUndefinedVariable: ‘ansible_ssh_host‘ is undefined.是肯定会遇到的,参考我这篇 安全性限制 ansible提示 warning: now open files is 1024, and need to …

第三次作业

1、使用SQL语句ALTER TABLE修改curriculum表的“课程名称”列,使之为空。 alter table curriculum drop `课程名称`;运行结果:2、使用SQL语句ALTER TABLE修改grade表的“分数”列,使其数据类型为decimal(5,2)。 alter table grade MODIFY `分数` DECIMAL(5,2);运行结果:3、…

tarjan学习笔记

tarjan学习笔记 0.前置知识强连通图 在一个有向图中,若从任意一点可以到达其他所有点,则称之为强连通图强连通分量(SCC) 一个图中的极大强连通性质子图(强连通图的强连通分量是它本身) \(\small {极大强连通子图指一个不能加入另外的点的强连通子图(一个强连通子图可能包…

Educational Codeforces Round 155 (Rated for Div. 2)

Educational Codeforces Round 155 (Rated for Div. 2) A--C(未更新完)比赛链接 A. Rigged! 题目链接 就是一个比较简单的模拟就可以解决,如何判断能不能第一只需要考虑比他力量大的耐力是不是也比他大就行,而只要比他大,他就不可能第一,否则输出他的力量作为标杆就行,这样…