当前位置: 首页 > news >正文

mysql连接池的实现

目录

1 池化技术

2 什么是数据库连接池

3 为什么使用数据库连接池

3.1 不使用连接池

3.2 使用连接池

3.3 长连接和连接池的区别

4 数据库连接池运行机制

 5 连接池和线程池的关系

6 线程池设计要点

6.1 连接池设计逻辑

构造函数 

初始化

请求获取连接 

 归还连接 

析构连接池 

连接

6.2 mysql连接重连机制

问题


C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

1 池化技术

        池化技术能够减少资源对象的创建次数,提高程序的响应性能,特别是在高并发下这种提高更加明显。

        使用池化技术缓存的资源对象有如下共同特点:

1. 对象创建时间长;

2. 对象创建需要大量资源;

3. 对象创建后可被重复使用

像常见的线程池、内存池、连接池、对象池都具有以上的共同特点。

2 什么是数据库连接池

        定义:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。

        大白话:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。

        这里讲的数据库,不单只是指Mysql,也同样适用于Redis。

3 为什么使用数据库连接池

1. 资源复用

        由于数据库连接得到复用,避免了频繁的创建、释放连接引起的性能开销,在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。

2. 更快的系统响应速度

        数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了从数据库连接初始化和释放过程的开销,从而缩减了系统整体响应时间。

3. 统一的连接管理,避免数据库连接泄露

        在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄露。

3.1 不使用连接池

1. TCP建立连接的三次握手(客户端与MySQL服务器的连接基于TCP协议)

2. MySQL认证的三次握手

3. 真正的SQL执行

4. MySQL的关闭

5. TCP的四次握手关闭

        可以看到,为了执行一条SQL,需要进行TCP三次握手,Mysql认证、Mysql关闭、TCP四次挥手等其他操作,执行SQL操作在所有的操作占比非常低。

优点:实现简单 省了连接池的设计。

缺点:每一次发起SQL操作都经历TCP建立连接、数据库用户身份验证、数据库用户登出、TCP断开连接。

  1. 网络IO较多
  2. 带宽利用率低
  3. QPS较低
  4. 应用频繁低创建连接和关闭连接,导致临时对象较多,带来更多的内存碎片
  5. 在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)

3.2 使用连接池

        在连接池初始化的时候,会按照需求建立N个连接,但是之后的访问,都会从池里面取,复用初始化时创建的连接,直接执行sql语句。

优点:

1. 降低了网络开销

2. 连接复用,有效减少连接数。

3. 提升性能,避免频繁的新建连接。新建连接的开销比较大

4. 没有TIME_WAIT状态的问题

缺点:

  1. 设计较为复杂

3.3 长连接和连接池的区别

  1. 长连接是一些驱动、驱动框架、ORM工具的特性,由驱动来保持连接句柄的打开,以便后续的数据库操作可以重用连接,从而减少数据库的连接开销。
  2. 而连接池是应用服务器的组件,它可以通过参数来配置连接数、连接检测、连接的生命周期等
  3. 连接池内的连接,其实就是长连接。

4 数据库连接池运行机制

1. 从连接池获取或创建可用连接;

2. 使用完毕之后,把连接返回给连接池;

3. 在系统关闭前,断开所有连接并释放连接占用的系统资源;

 5 连接池和线程池的关系

连接池和线程池的区别

        线程池:主动调用任务。当任务队列不为空的时候从队列取任务取执行。比如去银行办理业务,窗口柜员是线程,多个窗口组成了线程池,柜员从排号队列叫号执行。

        连接池:被动被任务使用。当某任务需要操作数据库时,只要从连接池中取出一个连接对象,当任务使用完该连接对象后,将该连接对象放回到连接池中。如果连接池中没有连接对象可以用,那么该任务就必须等待。比如去银行用笔填单,笔是连接对象,我们要用笔的时候去取,用完了还回去。

连接池和线程池设置数量的关系

  1. 一般线程池线程数量和连接池连接对象数量一致;
  2. 一般线程执行任务完毕的时候归还连接对象;

6 线程池设计要点

使用连接池需要预先建立数据库连接。

线程池设计思路:

1. 连接到数据库,涉及到数据库ip、端口、用户名、密码、数据库名字等;

        a.连接的操作,每个连接对象都是独立的连接通道,它们是独立的

        b.配置最小连接数和最大连接数

2. 需要一个队列管理他的连接,比如使用list;

3. 获取连接对象:

4. 归还连接对象;

5. 连接池的名字

6.1 连接池设计逻辑

构造函数 

string m_pool_name;             // 连接池名称string m_db_server_ip;       // 数据库ipuint16_t m_db_server_port;   // 数据库端口string m_username;           // 用户名string m_password;           // 用户密码string m_db_name;            // db名称int m_db_cur_conn_cnt;       // 当前启用的连接数量int m_db_max_conn_cnt;       // 最大连接数量CDBPool::CDBPool(const char *pool_name, const char *db_server_ip, uint16_t db_server_port,const char *username, const char *password, const char *db_name, int max_conn_cnt)
{m_pool_name = pool_name;m_db_server_ip = db_server_ip;m_db_server_port = db_server_port;m_username = username;m_password = password;m_db_name = db_name;m_db_max_conn_cnt = max_conn_cnt;    //m_db_cur_conn_cnt = MIN_DB_CONN_CNT; // 最小连接数量
}

初始化

CDBConn::CDBConn(CDBPool *pPool)
{m_pDBPool = pPool;m_mysql = NULL;
}CDBConn::~CDBConn()
{if (m_mysql){mysql_close(m_mysql);}
}int CDBConn::Init()
{m_mysql = mysql_init(NULL); // mysql_标准的mysql c client对应的apiif (!m_mysql){LOG_ERROR << "mysql_init failed";return 1;
}my_bool reconnect = true;mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);   // 配合mysql_ping实现自动重连
mysql_options(m_mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4"); // utf8mb4和utf8区别// ip 端口 用户名 密码 数据库名if (!mysql_real_connect(m_mysql, m_pDBPool->GetDBServerIP(), m_pDBPool->GetUsername(), m_pDBPool->GetPasswrod(),m_pDBPool->GetDBName(), m_pDBPool->GetDBServerPort(), NULL, 0)){LOG_ERROR << "mysql_real_connect failed: " << mysql_error(m_mysql);return 2;}return 0;
}int CDBPool::Init()
{// 创建固定最小的连接数量for (int i = 0; i < m_db_cur_conn_cnt; i++){CDBConn *pDBConn = new CDBConn(this);int ret = pDBConn->Init();if (ret){delete pDBConn;return ret;}m_free_list.push_back(pDBConn);}// log_info("db pool: %s, size: %d\n", m_pool_name.c_str(), (int)m_free_list.size());return 0;
}

请求获取连接 

/**TODO: 增加保护机制,把分配的连接加入另一个队列,这样获取连接时,如果没有空闲连接,*TODO: 检查已经分配的连接多久没有返回,如果超过一定时间,则自动收回连接,放在用户忘了调用释放连接的接口* timeout_ms默认为 0死等* timeout_ms >0 则为等待的时间*/
CDBConn *CDBPool::GetDBConn(const int timeout_ms)
{std::unique_lock<std::mutex> lock(m_mutex);if (m_abort_request){LOG_WARN << "have aboort";return NULL;}if (m_free_list.empty()) // 2 当没有连接可以用时{// 第一步先检测 当前连接数量是否达到最大的连接数量if (m_db_cur_conn_cnt >= m_db_max_conn_cnt) // 等待的逻辑{// 如果已经到达了,看看是否需要超时等待if (timeout_ms <= 0) // 死等,直到有连接可以用 或者 连接池要退出{m_cond_var.wait(lock, [this] {// 当前连接数量小于最大连接数量 或者请求释放连接池时退出return (!m_free_list.empty()) | m_abort_request;});}else{// return如果返回 false,继续wait(或者超时),  如果返回true退出wait// 1.m_free_list不为空// 2.超时退出// 3. m_abort_request被置为true,要释放整个连接池m_cond_var.wait_for(lock, std::chrono::milliseconds(timeout_ms), [this] {return (!m_free_list.empty()) | m_abort_request; });// 带超时功能时还要判断是否为空if (m_free_list.empty()) // 如果连接池还是没有空闲则退出{return NULL;}}if (m_abort_request){LOG_WARN << "have abort";return NULL;}}else // 还没有到最大连接则创建连接{CDBConn *pDBConn = new CDBConn(this); //新建连接int ret = pDBConn->Init();if (ret){LOG_ERROR << "Init DBConnecton failed";delete pDBConn;return NULL;}else{m_free_list.push_back(pDBConn);m_db_cur_conn_cnt++;// log_info("new db connection: %s, conn_cnt: %d\n", m_pool_name.c_str(), m_db_cur_conn_cnt);}}}CDBConn *pConn = m_free_list.front(); // 获取连接m_free_list.pop_front();              // STL 吐出连接,从空闲队列删除return pConn;
}

 归还连接 

void CDBPool::RelDBConn(CDBConn *pConn)
{std::lock_guard<std::mutex> lock(m_mutex);list<CDBConn *>::iterator it = m_free_list.begin();for (; it != m_free_list.end(); it++) // 避免重复归还{if (*it == pConn){break;}
}if (it == m_free_list.end()){// m_used_list.remove(pConn);m_free_list.push_back(pConn);m_cond_var.notify_one(); // 通知取队列}else{LOG_WARN << "RelDBConn failed";// 不再次回收连接}
}

析构连接池 

// 释放连接池
CDBPool::~CDBPool()
{std::lock_guard<std::mutex> lock(m_mutex);m_abort_request = true;m_cond_var.notify_all(); // 通知所有在等待的for (list<CDBConn *>::iterator it = m_free_list.begin(); it != m_free_list.end(); it++){CDBConn *pConn = *it;delete pConn;}m_free_list.clear();
}

连接

给每个池分配不同的名称,那么就可以用多个连接池实现不同的业务。池名

6.2 mysql连接重连机制

1. 设置启用(当发现连接断开时的)自动重连

my_bool reconnect = true;mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect); // 配合mysql_ping实现自动重连

2. 检测连接是否正常

int STDCALL mysql_ping(MYSQL *mysql);

描述:

        检查与服务端的连接是否正常。连接断开时,如果自动重新连接功能未被禁用,则尝试重新连接服务器。该函数可被客户端用来检测闲置许久以后,与服务端的连接是否关闭,如有需要,则重新连接。

返回值:

        连接正常,返回0;如有错误发生,则返回非0值。返回非0值并不意味着服务器本身关闭掉,也有可能是网络原因导致网络不通。

问题

4个连接池对象和4个线程使用4个连接池做同样的事情吗?还是区分每个线程做不同的事情。

答:连接池只是提供了连接对象,提供了一条连接通道,至于调用者要拿这个连接对象做什么业务是用调用者取决定的。出于业务解耦合的场景,也可以设置不同的线程池和不同的连接池应对不同的业务,比如即时通讯写入聊天记录和读取聊天记录采用不同的线程池和对象池。

相关文章:

mysql连接池的实现

目录 1 池化技术 2 什么是数据库连接池 3 为什么使用数据库连接池 3.1 不使用连接池 3.2 使用连接池 3.3 长连接和连接池的区别 4 数据库连接池运行机制 5 连接池和线程池的关系 6 线程池设计要点 6.1 连接池设计逻辑 构造函数 初始化 请求获取连接 归还连接 析…...

哪种类型蓝牙耳机佩戴最舒服?舒适度最好的蓝牙耳机推荐

如果您想在外出时听自己喜欢的音乐&#xff0c;您需要佩戴耳机&#xff0c;当前的耳机都足够小&#xff0c;可以将它们放在口袋里&#xff0c;即使它们在充电盒中也是如此&#xff0c;舒适度一直都是人们所追求的&#xff0c;舒适之余&#xff0c;佩戴同样稳固更加令人安心&…...

2020蓝桥杯真题洁净数 C语言/C++

题目描述 小明非常不喜欢数字 2&#xff0c;包括那些数位上包含数字 2 的数。如果一个数的数位不包含数字 2&#xff0c;小明将它称为洁净数。 请问在整数 1 至 n 中&#xff0c;洁净数有多少个&#xff1f; 输入描述 输入的第一行包含一个整数 n(1≤n≤10^6)。 输出描述 输…...

【随笔二】useReducer详解及其应用场景

前言 useReducer 实际上是 useState 的升级版&#xff0c;都是用来存储和更新 state&#xff0c;只是应用的场景不一样。 一般情况下&#xff0c;我们使用 useState 就足够项目需要了&#xff0c;不多当遇到以下场景时&#xff0c;使用useReducer 会更好些 。 状态逻辑复杂&…...

打怪升级之istringstream介绍

istringstream类 istringstream本质不是类&#xff0c;是一个宏&#xff0c;或者说是一个流&#xff1a; typedef basic_istringstream<char> istringstream;istringstream从basic_istringstream的char专用项而来。这一部分让人看得摸不着头脑的原因是因为大量使用了st…...

系统重装漏洞

zzcms系统重装漏洞 一、配置zzcms环境 1. 使用小皮搭建zzcms框架 2. 安装zzcms 按照下面的操作进行,傻瓜式操作即可 3. 打开网站 二、漏洞利用 在访问install目录的默认文件后,会出现zzcms安装向导 http://www.zzcms.com/install/index.php 但是会显示 “安装向导…...

C++面向对象编程之五:友元(friend)

C中&#xff0c;允许一个类的非共有成员被这个类授予友元&#xff08;friend&#xff09;关系的全局函数&#xff0c;另一个类&#xff0c;或另一个类中的成员函数访问。友元不是一个类中的成员&#xff0c;所以它们不受声明出现部分的访问权限&#xff08;public&#xff0c;p…...

[手写OS]动手实现一个OS 之X86实模式下的汇编开发

[手写OS]动手实现一个OS 之X86实模式下的汇编开发 x86实模式下 汇编开发是一个 intel x86实模式中的汇编程序开发类型。它涉及操纵几个16位处理器寄存器&#xff0c;并仅处理内存中的物理地址&#xff08;与受保护模式相对&#xff09;。 这种类型的编程中最广为人知的应用就…...

【Linux内核二】常用的网络丢包错包debug工具介绍

目录 ifconfig Ifconfig输出各字段简述 txqueuelen RX和TX的errors指哪些错误 dropped与overruns的区别 常用ifconfig配置命令 显示网卡信息 启动关闭指定网卡 配置和删除ip地址 修改MAC地址 启用和关闭ARP协议 设置最大传输单元 设置网卡的promiscuous模式 设置…...

qt控件增加渐变色效果

ui->returnBtn->setStyleSheet("color: rgb(0, 0, 0);""background:qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, ""stop:0 #5f5f5f, stop:0.5 #ffffff, stop:0.98 #5f5f5f);""border:none;");效果如下图&#xff1a; …...

【node : 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 最全面有效的解决方案】

执行nodejs文件错误&#xff1a; 这个错误提示通常是由于你的系统无法识别 "node" 命令&#xff0c;可能是由于你没有正确地安装或配置 Node.js 环境变量。 问题描述 ​​​​​​​​​​​​​​ 原因分析&#xff1a; 可能原因包括&#xff1a; 1.Node.js未正确安…...

打怪升级之字符串的分界符与字符串替换

流的字符串分界符 在C的iostream中&#xff0c;有流的字符串分界符&#xff1a; " “和”"都代表简单的分隔。 因此&#xff0c;使用流来做字符串分隔的话&#xff0c;有一个比较简单的方案就是将原定义的分隔符通过替换的方式变成流的分隔符。然后再录入流中就能…...

载荷台子使用方式

载荷自动测量台子使用方法 电源开关旋转到1&#xff0c;开启电源开启台子微机开关&#xff0c;开启电脑&#xff08;winxp&#xff09;开启台子载荷开关&#xff0c;启动载荷台子点击电脑动标图标&#xff0c;开启软件放入载荷&#xff0c;弹性体向上&#xff0c;载荷台子压头压…...

1005 继续(3n + 1)猜想

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。 当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递推过程中遇到的每一个数。例如对 n3 进行验证的时候&#xff0c;我们需要计算 3、5、8、4、2、1&a…...

VMware15配置NAT模式联通网络

最近为了测试C# 开发的桌面应用程序悬浮球的兼容性&#xff0c;在虚拟机上安装了win7系统和xp系统&#xff0c;之前也安装过黑苹果系统&#xff0c;但是win系统倒是第一次安装&#xff0c;在win7系统联网的时候&#xff0c;踩了一些坑&#xff0c;整理纪录一下。 设置主物理机配…...

doPost的实际使用

目录 前言 一、doPost是什么&#xff1f; 二、使用步骤 1.doPost的请求方法 2.需要引入依赖 总结 前言 本章主要记录一下doPost的请求公用方法的使用。 一、doPost是什么&#xff1f; 它其实就是一个http的post请求方式。 二、使用步骤 1.doPost的请求方法 当我们系…...

2017年MathorCup数学建模A题流程工业的智能制造解题全过程文档及程序

2017年第七届MathorCup高校数学建模挑战赛 A题 流程工业的智能制造 原题再现&#xff1a; “中国制造 2025”是我国制造业升级的国家大战略。其技术核心是智能制造&#xff0c;智能化程度相当于“德国工业 4.0”水平。“中国制造 2025”的重点领域既包含重大装备的制造业&…...

HNU-电子测试平台与工具2-数模转换

数模转换实验 计科XXXX wolf 工程文件我也一并上传了 D级任务 一.实验任务 对74194进行仿真验证&#xff0c;掌握Quartus仿真的基本原则和常规步骤&#xff0c;记录移位寄存器的数据读写&#xff0c;并描述仿真波形&#xff0c;分析结果。 二.实验过程 1.电路连接 2.功能…...

CentOS7安装Telnet客户端和服务端和使用方式

在执行telnet时会提示命令不存在。Telnet服务的配置步骤如下:一、检测是否安装telnet软件包&#xff08;通常要两个&#xff09;1、telnet-client (或 telnet)&#xff0c;这个软件包提供的是 telnet 客户端程序&#xff1b;2、telnet-server 软件包&#xff0c;这个才是真正的…...

脂肪毒性的新兴调节剂——肠道微生物组

谷禾健康 肠道微生物组与脂质代谢&#xff1a;超越关联 脂质在细胞信号转导中起着至关重要的作用&#xff0c;有助于细胞膜的结构完整性&#xff0c;并调节能量代谢。 肠道微生物组通过从头生物合成和对宿主和膳食底物的修饰产生了大量的小分子。 最近的研究表明&#xff0c;由…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...