池化设计之数据库连接池

前言

一般数据库操作、主机操作等经常会涉及到会话,什么是会话,会话在日常生活中就是指两个人或者多个人直接的交流,同样的在IT行业会话一般是指客户端和服务端之间的通信交流。比如数据库,如果使用可视化界面做为客户端和数据库服务进行交互通常就会建立一个“会话”,在软件中一般称为连接。

开发者们在程序中经常也会创建客户端用来和服务端进行通信,通信完成后和服务器断开连接。如果程序中在使用到数据库的地方都创建一个连接,那么服务端必然会承受不了这么多的连接,因此产生了池的概念,池,顾名思义就是一个可以存储某种物质的容器,上述的场景中,池存储的便是数据库连接。创建出来的连接在程序A使用完成后不需要断开,只需要归还到池中即可。当程序B需要时也直接从池中获取。这样就达到了一个资源复用的效果。即节约了创建连接的时间,也缓解了数据库的压力。

连接池的实现

1、抽象连接池接口


/*** @program: lifeguard* @description: 连接池接口* @author: Cheng Zhi* @create: 2024-01-15 14:10**/
public interface IPool<T> extends Closeable {/*** 获取连接* @return* @throws Exception*/public T poll();/*** 归还连接* @param conn*/public void offer(T conn);/*** 查询状态* @return*/public PoolStatus getStatus();/*** 获得数据源* @return*/Object getDatasource();/*** 关闭多余的连接*/public void closeConnectionTillMin();/*** 关闭连接池,包括释放其中全部的连接*/void close();
}

2、连接池实现

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;/*** @program: lifeguard* @description: JDBC连接池* @author: Cheng Zhi* @create: 2024-01-15 14:09**/
public class JdbcConnectionPool implements IPool<JdbcConnection> {Logger logger = LoggerFactory.getLogger(JdbcConnectionPool.class);private DataSource datasource;/*** 最大连接数*/private int max;/*** 最小连接数*/private int min;/*** 被取走的连接数*/private AtomicInteger used = new AtomicInteger();/*** 空闲连接数*/private final BlockingQueue<JdbcConnection> freeConns;/*** 连接池是否被关闭*/private boolean isClosed = false;public JdbcConnectionPool(int min, int max, DataSource ds) {this.min = min;this.max = max;this.datasource = ds;this.freeConns = new LinkedBlockingQueue<JdbcConnection>(max);PoolReleaseWorker.getInstance().addPool(this);}@Overridepublic JdbcConnection poll(){try {JdbcConnection conn = freeConns.poll();if(conn != null){used.incrementAndGet(); // 计数器自增return conn;}if (used.get() < max) {// 尝试用新连接used.incrementAndGet(); // 必须立刻累加计数器,否则并发的线程会立刻抢先创建对象,从而超出连接池限制conn = new JdbcConnection(datasource.getConnection(), this);} else {used.incrementAndGet(); // 提前计数,并发下为了严格阻止连接池超出上限,必须这样做conn = freeConns.poll(5000000000L, TimeUnit.NANOSECONDS);// 5秒if (conn == null) {used.decrementAndGet();// 回滚计数器throw new SQLException("No connection avaliable now." + getStatus());}conn = ensureOpen(conn);}return conn;} catch (Exception e) {logger.error("从连接池获取连接异常", e);}return null;}/*** 检查连接是否可用,如果不可以则新建* @param conn* @return* @throws SQLException*/private JdbcConnection ensureOpen(JdbcConnection conn) throws SQLException {boolean closed = true;try {closed = conn.isClosed();} catch (SQLException e) {conn.closePhysical();}if (closed) {return new JdbcConnection(datasource.getConnection(),this);} else {return conn;}}@Overridepublic void offer(JdbcConnection conn) {if (isClosed) {// 如果连接池已经被关闭,该连接意味着无家可归,应及时关闭conn.closePhysical();}boolean success = freeConns.offer(conn);if (!success) {// 归还连接失败,关闭物理连接conn.closePhysical();}used.decrementAndGet();}@Overridepublic PoolStatus getStatus() {int used = this.used.get();int free = freeConns.size();return new PoolStatus(max, min, used + free, used, free);}@Overridepublic DataSource getDatasource() {return this.datasource;}/*** 关闭多余连接,不需要人为关闭,PoolReleaseWorker会自动关闭。*/@Overridepublic void closeConnectionTillMin() {if (freeConns.size() > min) {JdbcConnection conn;while (freeConns.size() > min && (conn = freeConns.poll()) != null) {conn.closePhysical();}}}@Overridepublic void close(){max = 0;min = 0;closeConnectionTillMin();PoolReleaseWorker.getInstance().removePool(this);this.isClosed = true;}@Overridepublic void closePhysical() {this.close();}@Overrideprotected void finalize() throws Throwable {this.close();super.finalize();}
}

连接池自动缩容

池,一般都会设计成可以自动根据使用需求来进行自动扩容和缩容,扩容的实现一般相对简单,比如上面的代码中当前连接不够用且没有达到指定的最大值时即可继续扩容。而缩容则相对要复杂一些,因为连接池本身并不知道什么时候是缩容的最佳时机,如果在归还连接时将立即将超出核心连接数的多余连接关闭的话,由于此时并不能确定连接够不够用,如果不够用还要继续扩容,这样的话连接池的设计就没有意义了,因此这里新开一个线程专门进行线程的收缩和资源释放。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.concurrent.ConcurrentLinkedQueue;/*** @program: lifeguard* @description: 负责释放大于核心连接数的连接* @author: Cheng Zhi* @create: 2024-01-15 17:13**/
public class PoolReleaseWorker extends Thread {Logger logger = LoggerFactory.getLogger(PoolReleaseWorker.class);private static PoolReleaseWorker prw = new PoolReleaseWorker();/*** 保存所有的连接池,可以是jdbc连接池,也可以是ssh连接池*/private final ConcurrentLinkedQueue<IPool<?>> pools = new ConcurrentLinkedQueue<IPool<?>>();private boolean alive = true;/*** 清除多余连接线程运行间隔时间*/private static final int SLEEP_TIME = 60 * 1000;private PoolReleaseWorker() {super("pool-release-worker");setDaemon(true);}public void addPool(IPool<?> ip) {pools.add(ip);synchronized (this) {if (!isAlive() && alive) {start();}}}public void removePool(IPool<?> ip) {pools.remove(ip);}public static PoolReleaseWorker getInstance() {return prw;}public void close() {this.alive = false;}@Overridepublic void run() {ThreadUtils.doSleep(SLEEP_TIME);try {while (alive) {for (IPool<?> pool : pools) {try {pool.closeConnectionTillMin();} catch (Exception e) {logger.error("release connecton pool error", e);}}ThreadUtils.doSleep(SLEEP_TIME);}} catch (Exception e) {logger.error("释放连接异常", e);}}
}

总结

连接池的核心类都贴出来了,一些简单的比如JdbcConnection这些类就没有贴出来了,这个只是对jdbc中的connection进行了一个包装,大家可以看懂即可。

这样一个连接池就设计完成了,如果扩展一下还可以支持SSH或者其他协议的连接。虽然设计可能并不是很巧妙,但是以上案例也将池的思想体现出来了,如果大家有更好的想法,也可以一起沟通。

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

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

相关文章

牛顿法与拟牛顿法

文章目录 牛顿法&拟牛顿法1 牛顿法2 拟牛顿法2.1 对称秩1校正2.2 DFP2.3 BFGS 牛顿法&拟牛顿法 设无约束优化问题&#xff1a; min ⁡ f ( x ) , x ∈ R n \min f(x),{\kern 1pt} \,x \in {R^n} minf(x),x∈Rn 1 牛顿法 基本思想&#xff0c;通过泰勒二阶展开&…

Prometheus 容器化部署

实验部署 工作中是基于kube-api的自动发现 1、创建账户绑定集群 kubectl create serviceaccount monitor -n monitor-sa #创建账户 kubectl create clusterrolebinding monitor-clusterrolebinding -n monitor-sa --clusterrolecluster-admin --serviceaccountmonitor-sa:…

FileViewer纯前端预览项目Vue2 demo

FileViewer 项目Vue2 demo 本demo基于vue-clijsvue2.x构建&#xff0c;如果您需要vue3版本的demo&#xff0c;请前往main分支。 适用于Vue2 Webpack&#xff0c;本集成方法要求最低Webpack版本为5&#xff0c;也就是Vue Cli Service 5.0.0以上&#xff0c;当然&#xff0c;if…

13.前端--CSS-盒子模型

1.盒子模型的组成 CSS 盒子模型本质上是一个盒子&#xff0c;封装周围的 HTML 元素&#xff0c;它包括&#xff1a;边框、外边距、内边距、和 实际内容 2.边框&#xff08;border&#xff09; 2.1 边框的使用 1、border设置元素的边框。边框有三部分组成:边框宽度(粗细) 边框…

国网四川宜宾供电公司:基于“RPA+AI”融合技术的电网设备隐患缺陷智能化识别应用

推荐单位&#xff1a;国网四川省电力公司宜宾供电公司 本文作者&#xff1a;杨鑫、唐龙、钟睿、李小航、孙雪冬 摘 要&#xff1a;为推进电力企业生产业务数字化转型&#xff0c;提高基层班组数字化运维水平。本文通过一线班组对变电站视频巡视、设备故障判断应用场景需求分析…

C++-内存管理(1)

1. C/C内存分布 首先我们需要知道&#xff0c;在C中的内存分为5个区。 1. 栈 又叫堆栈 -- 非静态局部变量 / 函数参数 / 返回值等等&#xff0c;栈是向下增长的。 2. 内存映射段 是高效的 I/O 映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口 创建…

【2023地理设计组一等奖】基于GIS的桥梁隧道三维建模与可视化

作品介绍 1 设计背景和意义 随着我国基础建设规模不断扩大和深入,构建桥梁可视化管理模型,全面推动智慧桥梁,已成为现代隧道桥梁建设行业的发展趋势。传统的桥梁建模工作需要复杂的算法设计并需要熟练编程实践技能,实现周期长。开发自主知识版权的桥梁建模软件系统或专用插…

在线mockjson

在线mockjson体验地址 在调一个问题的时候&#xff0c;但是问题的数据可能并不能随着想到的场景就变化&#xff0c;譬如说又个数组长度的情况&#xff0c;可能默认的情况下是返回4个元素&#xff0c;但是想要返回为空的时候&#xff0c;如果联系服务给改一下&#xff0c;那么流…

防火墙知识普及详解,使用TOR Router把TOR作为默认网关,增加隐私/匿名性

防火墙知识普及详解,使用TOR Router把TOR作为默认网关,增加隐私/匿名性。 #################### 免责声明:工具本身并无好坏,希望大家以遵守《网络安全法》相关法律为前提来使用该工具,支持研究学习,切勿用于非法犯罪活动,对于恶意使用该工具造成的损失,和本人及开发者…

Abp 从空白WebApplication开始

开发环境&#xff1a;VS2022、.NET6 1、创建项目&#xff1a;BasicAspNetCoreApplication 2、NuGet添加&#xff1a;Volo.Abp.AspNetCore.Mvc和Volo.Abp.Autofac&#xff0c;如下图所示&#xff1a; 3、开始写代码&#xff0c;目录如下图所示&#xff1a; 3.1、添加启动模块Ap…

使用make_grid多批次显示网格图像(使用CIFAR数据集介绍)

背景介绍 在机器学习的训练数据集中&#xff0c;我们经常使用多批次的训练来实现更好的训练效果&#xff0c;具体到cv领域&#xff0c;我们的训练数据集通常是[B,C,W,H]格式&#xff0c;其中&#xff0c;B是每个训练批次的大小&#xff0c;C是图片的通道数&#xff0c;如果是1…

接口请求,上传文件报500异常

异常响应 {"timestamp": "2024-01-29T06:39:28.82000:00","status": 500,"error": "Internal Server Error","path": "/test/upload" }服务端日志 服务端无日志打印 分析方向 nginx配置 nginx配置…

如何多个excel中的数据分发到多个excel中去

这个问题之前有一个文章我写了这个方法&#xff0c;但是后来发现效率太低了&#xff0c;于是再次更新一下对应的技术方案&#xff0c;提速5000倍。 一下代码主要实现的功能&#xff1a; 我有5000多个excel文件&#xff0c;每个文件是一只股票从上市至今的日K交易数据&#xff0…

Python网络拓扑库之mininet使用详解

概要 网络工程师、研究人员和开发人员需要进行各种网络实验和测试&#xff0c;以评估网络应用和协议的性能&#xff0c;以及解决网络问题。Python Mininet是一个功能强大的工具&#xff0c;它允许用户创建、配置和仿真复杂的网络拓扑&#xff0c;以满足各种实际应用场景。本文…

计算机二级Python选择题考点——Python语言程序设计Ⅰ

在Python中&#xff0c;变量名的命名规则:以字母或下划线开头&#xff0c;后面跟字母、下划线和数字&#xff0c;不能以数字开头。在Python语言中&#xff0c;可以作为源文件后缀名的是py。chr(x)和ord(x)函数用于在单字符和Unicode编码值之间进行转换。Python语言中用来表示代…

运行yolo v8 YOLOv8-CPP-Inference C++部署遇到的问题

环境&#xff1a; openCv:4.8.0 torch: 2.0.0 cuda:cuda_11.7.r11.7 遇到问题1&#xff1a; (tools) rogi7:~/my_file/obj/ultralytics/examples/YOLOv8-CPP-Inference/build$ ./Yolov8CPPInference Running on CUDA [ WARN:00.039] global net_impl.cpp:178 setUpNet DNN mo…

Java 面向对象进阶 01(黑马)

static案例代码&#xff1a; 代码&#xff1a; public class Student {private String gender;private String name;private int age;public static String teacherName ;public Student() {}public Student(String gender, String name, int age) {this.gender gender;this.…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--大模型、扩散模型、视觉语言导航

专属领域论文订阅 VX 关注{晓理紫}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起免费…

费一凡:土木博士的自我救赎之道 | 提升之路系列(五)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

Linux true/false区分

bash的数值代表和其它代表相反&#xff1a;0表示true&#xff1b;非0代表false。 #!/bin/sh PIDFILE"pid"# truenginx进程运行 falsenginx进程未运行 checkRunning(){# -f true表示普通文件if [ -f "$PIDFILE" ]; then# -z 字符串长度为0trueif [ -z &qu…