【数据库连接池】04:连接池空闲连接回收

连接池空闲连接回收


OVERVIEW

  • 连接池空闲连接回收
      • 1.需求分析
      • 2.Connection添加字段
      • 3.CommonConnectionPool中调用刷新
      • 4.CommonConnectionPool中定时扫描
        • CommonConnectionPool.h
        • CommonConnectionPool.cpp

1.需求分析

多余的连接如果超过指定的时间,还没有再次被使用到,就需要将连接进行回收,从而节省服务器资源,

实现方案:

  1. 在Connection类中添加_alivetime字段,用于记录连接进入空闲状态后的起始时间,
  2. 每次入队或者出队时都将Connection连接对象的_alivetime字段进行刷新,
  3. 启动一个定时线程,定时扫描超过maxIdleTime的空闲连接,进行多余连接的回收操作

2.Connection添加字段

#ifndef _CONNECTION_H
#define _CONNECTION_H#include <ctime>
#include <string.h>
#include <iostream>
#include <mysql/mysql.h>
using namespace std;#define LOG(str)									\cout << __FILE__ << ":" << __LINE__ << " " <<	\__TIMESTAMP__ << ":" << str << endl;// 封装Connection对象 实现数据库增删改查
class Connection {
public:// 初始化数据库连接Connection();// 释放数据库连接资源~Connection();// 连接数据库bool connect(string ip, unsigned short port, string user, string password, string dbname);// 更新数据库操作 insert delete updatebool update(string sql);// 刷新连接的起始空闲时间点void refreshAliveTime() { _alivetime = clock(); }// 返回连接存活的时长clock_t getAliveTime() const { return clock() - _alivetime; }
private:// 表示和 MYSQL Server的一条连接MYSQL *_conn;// 进入空闲状态后的起始时间clock_t _alivetime;
};#endif

3.CommonConnectionPool中调用刷新

  1. 在初始化连接池时,添加刷新Connection连接的alivetime

    // 初始化连接池
    ConnectionPool::ConnectionPool() {// 1.加载配置项if (!loadConfigFile()) return;// 2.创建初始数量的连接for (int i = 0; i < _initSize; ++i) {Connection *p = new Connection();p->connect(_ip, _port, _username, _password, _dbname);p->refreshAliveTime();_connectionq.push(p);_connectionCnt++;}// 3.启动一个新的线程作为连接的生产者thread connProducer(std::bind(&ConnectionPool::produceConnTask, this));
    }
    
  2. 在消费者生产Connection连接时,刷新连接的alivetime

    // 生产者线程的线程函数
    void ConnectionPool::produceConnTask()
    {for (;;) {// 队列上锁unique_lock<mutex> lock(_queueMutex);// 若队列不空 生产者线程进入等待状态 并且将锁释放 等待为空while (!_connectionq.empty()) {condv.wait(lock);}// 连接数量没有到达上限 则继续创建新的连接if (_connectionCnt < _maxSize) {Connection *p = new Connection();p->connect(_ip, _port, _username, _password, _dbname);p->refreshAliveTime();_connectionq.push(p);_connectionCnt++;}// 通知消费者线程可以消费连接了condv.notify_all();}
    }
    
  3. 在消费者使用完毕,归还数据库连接时,需要刷新连接的alivetime

    // 返回连接对象 使用智能指针管理
    shared_ptr<Connection> sp(_connectionq.front(), [&](Connection *pcon){unique_lock<mutex> lock(_queueMutex);pcon->refreshAliveTime();_connectionq.push(pcon);
    });
    

4.CommonConnectionPool中定时扫描

启动一个定时线程,定时扫描超过maxIdleTime的空闲连接,进行多余连接的回收操作

CommonConnectionPool.h
#ifndef _COMMONCONNECTIONPOOL_H
#define _COMMONCONNECTIONPOOL_H#include <queue>
#include <string>
#include <mutex>
#include <atomic>
#include <thread>
#include <memory>
#include <functional>
#include <condition_variable>
#include "Connection.h"
using namespace std;// 实现连接池功能模块
class ConnectionPool {
public:// 获取连接池实例static ConnectionPool* getConnectionPool();// 获取数据库连接shared_ptr<Connection> getConnection();
private:ConnectionPool();// 加载外部配置文件bool loadConfigFile();// 生产新连接任务函数void produceConnTask();// 定时扫描空闲连接 并进行回收操作void collectConnTask();
private:// 连接池参数int _initSize;				// 初始连接量int _maxSize;				// 最大连接量int _maxIdleTime;			// 最大空闲时间int _connectionTimeout;		// 连接超时时间// 数据库信息string _ip;unsigned short _port;string _username;string _password;string _dbname;// 数据库连接存储队列queue<Connection*> _connectionq;		// 存储mysql连接的队列mutex _queueMutex;						// 维护连接队列的线程安全的互斥锁atomic_int _connectionCnt;				// 创建连接的数量 ++操作是线程安全的condition_variable condv;					// 条件变量 用于连接生产线程和连接消费线程间的通信
};#endif
CommonConnectionPool.cpp
// 初始化连接池
ConnectionPool::ConnectionPool() {// 1.加载配置项if (!loadConfigFile()) return;// 2.创建初始数量的连接for (int i = 0; i < _initSize; ++i) {Connection *p = new Connection();p->connect(_ip, _port, _username, _password, _dbname);p->refreshAliveTime();_connectionq.push(p);_connectionCnt++;}// 3.启动一个新的线程作为连接的生产者thread connProducer(std::bind(&ConnectionPool::produceConnTask, this));// 设置为守护线程connProducer.detach();// 4.启动一个新的线程 定时扫描超过maxIdleTime时间的空闲连接 对空闲连接进行回收操作thread connCollector(std::bind(&ConnectionPool::collectConnTask, this));// 设置为守护线程connCollector.detach();
}// 定时扫描空闲连接 并进行回收操作
void ConnectionPool::collectConnTask()
{for (;;) {// 通过调用sleep模拟定时效果this_thread::sleep_for(chrono::seconds(_maxIdleTime));// 扫描整个连接池队列 释放多余连接unique_lock<mutex> lock(_queueMutex);while (_connectionCnt > _initSize) {Connection *p = _connectionq.front();if (p->getAliveTime() < (_maxIdleTime * 1000)) break;_connectionq.pop();_connectionCnt--;delete p;//调用Connection的析构函数释放连接}}
}

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

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

相关文章

Android 9.0 系统默认显示电量百分比

Android 9.0 系统默认显示电量百分比 近来收到项目需求需要设备默认显示电量百分比&#xff0c;具体修改参照如下&#xff1a; /frameworks/base/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java private void updateShowPercent() {final boolean showin…

函数保留凸性的一些运算,限制为一条线

凸优化在学术研究中非常重要&#xff0c;经常遇到的问题是证明凸性。常规证明凸性的方式是二阶导数的黑塞矩阵为半正定&#xff0c;或者在一维函数时二阶导数大于等于零。但很多时候的数学模型并不那么常规、容易求导的&#xff0c;若能够知道一些保留凸性的运算&#xff0c;将…

linux 账号管理实例一,stdin,passwd复习

需求 账号名称全名次要用户组是否可登录主机密码 myuser1 1st usermygroup1yespasswordmyuser22st usermygroup1yespasswordmyuser33st user无nopassword 第一&#xff1a;用户&#xff0c;和用户组创建&#xff0c;并分配有效用户组&#xff08;初始用户组是passwd里…

11.24 力扣优先队列

题目 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1] 思路&#xff1a;首先遍历整个数组&#xff0c;并…

Java中的过滤器、拦截器和aop

目录 1、过滤器、拦截器和aop有什么区别及各自的应用场景 2、拦截器和aop的区别是什么 3、举个例子 4、拦截器和过滤器有什么区别 1、过滤器、拦截器和aop有什么区别及各自的应用场景 Java中的过滤器&#xff08;Filter&#xff09;、拦截器&#xff08;Interceptor&#…

97.STL-查找算法 find

目录 STL-查找算法find 1.基本用法&#xff1a; 2.查找自定义类型&#xff1a; 3.查找范围&#xff1a; STL-查找算法find 在C的STL&#xff08;标准模板库&#xff09;中&#xff0c;find 算法用于在指定范围内查找指定值的元素。 功能描述&#xff1a; 查找指定元素&…

YOLOV8解读及推理代码

YOLOV8解读及推理代码 YOLOV8前言性能对比新的骨干网络新的 Ancher-Free 检测头新的损失函数环境配置训练基于python脚本基于命令行 推理pt模型推理onnx模型推理 YOLOV8 前言 YOLOv8并非一个全新的目标检测网络&#xff0c;而是在YOLOv5的基础上进行了升级。其主要升级包括&am…

ASCII sorting

描述 输入一个字符串&#xff0c;对其字符进行排序&#xff0c;输出其字符按ASCII码升序排列。 输入 无空格字符串 输出 按ASCII码升序输出其字符。 样例输入 and 样例输出 adn code&#xff08;c版本&#xff09; #include<stdio.h> #include<stdlib.h> // qs…

LeetCode [中等]和为 K 的子数组

给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 思路&#xff1a; sum: 当前位置的累积和。 如果以当前位置为结尾的数组中&#xff0c;存在和为k的子数组&#xff0c;那么&#xff…

c++之STL

首先我们来仔细研究string 首先我们需要实现string的构造函数和析构函数。有new就有delete. 然后我们实现size()和c_str()&#xff0c;其中c_str就是可以将string类型转换为char*类型返回。 通过运算符重载&#xff0c;我们就可以实现string的[]访问。 然后我们实现和append。 …

超声波水表的量程比是多少?

超声波水表是现代智能水表中的一种重要类型&#xff0c;它采用超声波技术来测量水流速度和体积。量程比作为超声波水表的一个重要指标&#xff0c;决定着其在不同流量范围内的测量性能和准确度。那么&#xff0c;超声波水表的量程比是多少呢&#xff1f; 量程比是指超声波水表最…

2.安装docker

目录 1 安装依赖 2 安装docker 3 测试 目前docker分为三类 Docker-CE(社区版),Docker-EE(企业版)和Moby。Moby是docker社区用户自己写的&#xff0c;所以Moby我们一般用不上 每一类的每一个版本中都有Edge与Stable版&#xff0c;Stable维护4个月&#xff0c;Edge维护1个…

u8g2图形库——丝滑菜单制作

目录 一、实物效果展示 二、丝滑菜单实现原理 三、代码开源 1.ui_bmp.h 2.ui.h 3.ui.c 一、实物效果展示 u8g2图形库——丝滑菜单制作 二、丝滑菜单实现原理 int ui_run(short *a,short *a_tag,uint8_t step,uint8_t slow_cnt) //UI滑动效果 {uint8_t temp;…

试写一算法将两个递增有序的带头结点的单链表合并为一个递增有序的带头结点的单链表。(利用原表结点空间)

试写一算法将两个递增有序的带头结点的单链表合并为一个递增有序的带头结点的单链表。 &#xff08;利用原表结点空间&#xff09; 比如现在要将下面两个链表合并&#xff0c;这里是要求利用原表空间 我们先创建一个辅助的链表L3&#xff0c;用p和q分别标记L1和L2的数据元素&…

L298N模块使用简介

接口作用ENA/ENB使用PWM调节马达转速&#xff08;调速&#xff09;左边一对接口接电机的正负极右边一对接口接电机正负极控制IN1,IN2 控制左边的2个接口的电压&#xff0c;IN1控制一个&#xff0c;IN2控制另外一个 IN1输入3.3V时&#xff0c;OUT1输出3.3v电压&#xff08;可能是…

NoSQL大数据存储技术思考题及参考答案

思考题及参考答案 第1章 绪论 1. NoSQL和关系型数据库在设计目标上有何主要区别&#xff1f; (1)关系数据库 优势&#xff1a;以完善的关系代数理论作为基础&#xff0c;具有数据模型、完整性约束和事务的强一致性等特点&#xff0c;借助索引机制可以实现高效的查询&#xf…

创建Asp.net MVC项目Ajax实现视图页面数据与后端Json传值显示

简述回顾 继上篇文章创建的mvc传值这里说明一下Json传值。在mvc框架中&#xff0c;不可避免地会遇到前台传值到后台&#xff0c;前台接收后台的值的情况&#xff08;前台指view&#xff0c;后台指controller&#xff09;&#xff0c;有时只需要从控制器中返回一个处理的结果&a…

execl点击单元格跳转

通过点击单元格跳转到其它单元格并获取单元格文本对数据进行过滤 平时我们通过超链接可以实现单元格跳转&#xff0c;但是并不能对数据进行过滤 此时我们可以用execl的宏来实现 实现的效果如图: 完整代码下载链接

【上海大学数字逻辑实验报告】二、组合电路(一)

一、 实验目的 熟悉TTL异或门构成逻辑电路的基本方式&#xff1b;熟悉组合电路的分析方法&#xff0c;测试组合逻辑电路的功能&#xff1b;掌握构造半加器和全加器的逻辑测试&#xff1b;学习使用可编程逻辑器件的开发工具 Quartus II设计电路。 二、 实验原理 异或门是数字…