首页 > 数据库 >【TinyWebServer】11数据库连接池

【TinyWebServer】11数据库连接池

时间:2023-09-25 22:36:01浏览次数:48  
标签:11 数据库 TinyWebServer connection pool 连接 连接池 con

基础知识

什么是数据库连接池?

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

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

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

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

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

为什么要创建连接池?

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

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

整体概述

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

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

本文内容

本篇将介绍数据库连接池的定义,具体的涉及到单例模式创建、连接池代码实现、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();

    //释放连接原子加1
    reserve.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;

        //清空list
        connList.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)

标签:11,数据库,TinyWebServer,connection,pool,连接,连接池,con
From: https://www.cnblogs.com/Wangzx000/p/17729019.html

相关文章

  • 11
    importpulpimportnumpyasnp#创建线性规划问题model=pulp.LpProblem("CrossDistribution",pulp.LpMaximize)#定义评审专家数量和作品数量num_experts=125num_works=3000#定义每位评审专家最多评审的作品数量和每份作品需要被评审的专家数量k=120#每......
  • 牛客周赛 Round 11
    https://ac.nowcoder.com/acm/contest/64593A题签到B题值得说得是对非降序的理解:非降序表示数组中的前一个数要<=下一个数C题也算dp,因为需要注意遍历顺序,计算的是所有子串的的权重,我们知道枚举所有子串需要\(O(n^2)\)的复杂度,按照本题数据范围显然不能\(O(n^3)\),我们只能在枚......
  • 11
    https://api.cn2.pw/api/v1/client/subscribe?token=d880fa160708bf1fc85b0774ebafb650&flag=clashwhttps://qiuyin.click/api/v1/client/subscribe?token=44bd8851fdc334f9775628c40befec2f......
  • CF1106D Lunar New Year and a Wander 题解
    CF1106D题解暑期学校军训第一天模拟赛的题,相对而言比较简单题意:题意其实很简单,就是有一个无向图,需要你从\(1\)号节点出发,然后一次遍历所有的点,输出其中字典序最小的遍历思路说说思路吧,这题既然要遍历图上所有点,那首先就会想到\(\texttt{BFS}\)或\(\texttt{DFS}\),可本题还......
  • 《看了受制了》第二十五天吗,5道题,合计119道题
    2023年9月24日今天下午,把atcoder翻译的弄成了一个ChatGpt的接口版本。优化了很多。牛客周赛13矩阵转置置题面理解就是语法,倒着输出即可。代码实现#include<iostream>#include<algorithm>#include<unordered_map>#include<cstring>#include<cstdio>#include<vect......
  • 20211314王艺达学习笔记3
    sh编程sh脚本与C程序·C程序必须先编译链接到一个二进制可执行文件,再通过主sh的子进程运行该二进制可执行文件;sh则可直接执行行命令。·sh脚本不需要main函数。编写sh脚本shell的基本语法主要就是如何输入命令运行程序以及如何在程序之间通过shell的一些参数提供便利手段来进......
  • 20211301 学习笔记3
    20211301《Unix/Linux系统编程》学习笔记3学习目标总结一下一门程序设计语言有哪些必备的要素和技能?这些要素和技能在shell脚本中是如果呈现出来的?教材知识总结10.1sh脚本定义:sh脚本是一个包含sh语句的文本文件、命令解释程序sh要执行该语句sh:sh是解释程序,逐行......
  • P3514 [POI2011] LIZ-Lollipop
    很神奇的题题意:给你一个由\(0\)和\(1\)组成的序列,给出\(q\)个询问,每次询问是否有原序列是否有总和为\(x\)的子段。考虑递推,但是小答案对大答案的影响不好算。考虑大区间对小区间的影响。设当前区间为\([l,r]\),总和为sum,有\(4\)种情况\(a[l]=2,a[r]=2\);这是无......
  • 20211316郭佳昊 《信息安全系统设计与实现(上)》第三周学习笔记
    一、任务要求[1]知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容(4分)我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问题核心是要求GPT:请你以苏格拉底的方式对我进行提问然后GPT就会......
  • 2023-2024-1 20211306 密码系统设计与实现课程学习笔记3
    20211306密码系统设计与实现课程学习笔记3学习任务详情自学教材第10章,提交学习笔记大家学习过Python,C,Java等语言,总结一下一门程序设计语言有哪些必备的要素和技能?这些要素和技能在shell脚本中是如果呈现出来的?知识点归纳以及自己最有收获的内容,选择至少2个知识点利用......