手写数据库连接池

news2024/11/25 0:50:48

数据库连接是个耗时操作.对数据库连接的高效管理影响应用程序的性能指标.

数据库连接池正是针对这个问题提出来的.

数据库连接池负责分配,管理和释放数据库连接.它允许应用程序重复使用一个现有的数据路连接,而不需要每次重新建立一个新的连接,利用数据库连接池将明显提升对数据库操作的性能.

数据库连接池技术方案:

1.C3P0

2.DBCP

3.Proxool

4.Tomcat jdbc Oppl

5.BoneCP

6.Druid

7.HikariCP

数据库连接池属于一种池化技术:

常见的有:http访问(httpclient),redis访问(redisPool),线程(线程池)等

新建个空项目

可能是版本原因idea创建空项目总要重启一下

设置下maven和encoding

新建模块

DataSource是JDK里的规范,用来专门放连接的.是一个连接工厂

自定义一个接口

里面需要实现的两个方法是:  其他的父接口的其他方式可以暂时不管

这样基础结构就有了

package com.pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @author hrui
 * @date 2023/9/10 3:06
 */
public class MyAbstractDataSource implements MyDataSourceInterface{

    private String url;

    private String driver;

    private String username;

    private String password;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return getConnection(username,password);
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return doGetConnection(username,password);
    }

    private Connection doGetConnection(String username, String password) throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }
}

上面三个方法,都是获得连接

下面用动态代理方式实现对数据库连接的代理

package com.pool;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;

/**
 * 采用动态代理实现对数据库连接的代理
 * @author hrui
 * @date 2023/9/10 3:45
 */
public  class ConnectionProxy implements InvocationHandler {

    //真正连接
    private Connection realConnection;

    //代理连接
    private Connection proxyConnection;

    //数据源对象
    private MyDataSource myDataSource;


    public ConnectionProxy(Connection realConnection, MyDataSource myDataSource) {
        //初始化真实连接和数据源
        this.realConnection = realConnection;
        this.myDataSource = myDataSource;

        //初始化代理连接...需要一个代理对象  JDK动态代理
        this.proxyConnection= (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),
                                                    new Class<?>[]{Connection.class},
                                                    this);

    }

    public Connection getRealConnection() {
        return realConnection;
    }

    public void setRealConnection(Connection realConnection) {
        this.realConnection = realConnection;
    }

    public Connection getProxyConnection() {
        return proxyConnection;
    }

    public void setProxyConnection(Connection proxyConnection) {
        this.proxyConnection = proxyConnection;
    }

    public MyDataSource getMyDataSource() {
        return myDataSource;
    }

    public void setMyDataSource(MyDataSource myDataSource) {
        this.myDataSource = myDataSource;
    }

    /**
     * 当调用Connection对象里面的任何方法时,该方法会进行拦截
     * 主要目的为了拦截Connection的close方法,当关闭时进行拦截,将Connection对象放入连接池中
     * 其他方法无需拦截
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取当前调用了Connection对象的什么方法
        String methodName=method.getName();
        if(methodName.equals("close")){
            //TODO 把连接放入连接池

            return null;
        }else{
            //其他方法
            return method.invoke(realConnection, args);
        }

    }
}

}

下面写个类继承MyAbstractDataSource  在里面放入连接池

package com.pool;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据源连接池
 * @author hrui
 * @date 2023/9/10 4:15
 */
public class MyDataSource extends MyAbstractDataSource{

    //空闲连接
    private final List<ConnectionProxy> idleConnections=new ArrayList<>();

    //激活的连接池
    private final List<ConnectionProxy> activeConnections=new ArrayList<>();
    
    //下面三个可以抽取放到父类抽象类中,由用户配置 
    //最大的连接数量
    private int poolMaxActiveConnection=10;

    //最大空闲连接数
    private int poolMaxIdIeConnection=5;

    //当连接都在使用时候,最大检出时间(等待时间),毫秒
    private int poolTimeToWait=20000;

    //用于同步监视器对象
    private final Object monitor=new Object();

    //用于同步监视器对象(关闭)
    //private final Object watch=new Object();

    /**
     * 重写:用于获取代理连接
     * @return
     * @throws SQLException
     */
    @Override
    public Connection getConnection() throws SQLException {
        ConnectionProxy connectionProxy=getConnectionProxy(super.getUsername(),super.getPassword());
        //返回代理连接
        return super.getConnection();
    }

    /**
     * 获取代理连接
     * @param username
     * @param password
     * @return
     */
    private ConnectionProxy getConnectionProxy(String username,String password) throws SQLException {
        //TODO
        //是否需要等待
        boolean wait=false;
        ConnectionProxy connectionProxy=null;
        //刚开始没有连接
        while(connectionProxy==null){
            synchronized (monitor){
                //看连接池有没有空闲连接,如果不为空,直接获取连接
                if(!idleConnections.isEmpty()){
                    connectionProxy=idleConnections.remove(0);
                 //如果是空的
                }else{
                    //没有空闲连接,那么需要获取新的连接(创建连接)
                    //这里先判断最大连接数是不是小于配置数量  10
                    if(activeConnections.size()<poolMaxActiveConnection){
                        //创建新连接  需要传入真实连接
                        connectionProxy=new ConnectionProxy(super.getConnection(),this);
                    }
                    //否则需要等待20秒   上面定义了poolTimeToWait=20000

                }
            }

            if(!wait){
                wait=true;
            }

            if(connectionProxy==null){
                try {
                    monitor.wait(poolTimeToWait);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //万一等待被线程打断,退出一下
                    break;
                }
            }

        }
        if(connectionProxy!=null){
            //连接对象不是空,说明已经拿到连接了,放入容器
            activeConnections.add(connectionProxy);
        }

        return connectionProxy;
    }

    //用于关连接
    //不是把连接关系,而是还给连接池
    public void closeConnection(ConnectionProxy connectionProxy){
        synchronized (monitor){
            //最大连接(激活连接)里删除
            activeConnections.remove(connectionProxy);

            //如果空闲连接<定义的数量则放入空闲连接
            if(idleConnections.size()<poolMaxIdIeConnection){
                idleConnections.add(connectionProxy);
            }
            //通知一下,唤醒上面哪个等待获取连接的线程
            monitor.notify();
        }
    }
}

那么代理对象中把连接还给连接池的方法也有了

就是当所有连接用完了,等待20秒的逻辑没写

下面测试自己写的连接池

新建模块  引入依赖

不想玩了

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

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

相关文章

文本生成模型如何解码

文章目录 解码方法Greedy SearchBeam SearchsamplingTemperature Samplingtop-k samplingTop-p (nucleus) samplingContrastive search 总结相关资源 语言模型如何对于一个给定输入生成相应的输出呢&#xff1f;答案是使用解码策略(decoding strategy)。这里对现有的解码策略做…

在vx1000中对目标属性值的函数修改方法

通过在函数中编辑GFX对象属性值&#xff0c;实现Y坐标相反的操作方法 有时需要对目标属性的x 、y坐标做负方向转换&#xff0c;就需要以下方法来实现 return input.ProY*(-1); return input.C0*(-1);

验收测试的内容和流程有哪些?

验收测试 信息化项目验收确认测试内容一般包括&#xff1a;测试(复核 ),资料评审 ,质量鉴定三部分。 (一)验收评测工作主要包括 :文档分析 ,方案制定 ,现场测试 ,问题单提交 ,测试报告 ; (二)验收测试内容主要包括 :检查 "合同 " 或"验收标准 "要求的所…

【Redis】2、Redis持久化和性能管理

Redis 高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供…

C++之构造函数列表使用默认值(一百九十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

发布订阅机制和点对点机制

【Go项目】25. 在 gin 中引入 WebSocket 和 Hub_哔哩哔哩_bilibili gorilla/websocket: Package gorilla/websocket is a fast, well-tested and widely used WebSocket implementation for Go. (github.com) 1.订阅发布机制 引用上面链接的内容 发布订阅的基本工作原理 在分…

AQS源码剖析,完整流程解读

目录 1 AQS是什么2 AQS加锁流程3 结构4 AQS方法概览5 AQS源码剖析5.1 加锁方法5.2 释放锁5.3 await等待5.4 signal唤醒 1 AQS是什么 ​ AQS即AbstractQueuedSynchronizer缩写&#xff0c;翻译为抽象队列同步器&#xff0c;是一种用来构建锁和同步器的框架。 平时使用较多的Ree…

【C++】常用排序算法

0.前言 1.sort #include <iostream> using namespace std;// 常用排序算法 sort #include<vector> #include<algorithm>//利用仿函数 打印输出 class myPrint { public:void operator()(int val){cout << val << " ";} };//利用普通函…

车载网络测试 - UDS诊断篇 - CANTP常用缩写

CANTP层规范常用缩写 缩写英文全称中文注释BRSbit rate switch比特率开关BSBlockSize块大小CAN controller area network控制器局域网CAN_DL CAN frame data link layer data length in bytesCAN 帧数据链路层数据长度&#xff08;以字节为单位&#xff09;CAN FDcontroller a…

[kingbase运维之奇怪的现象]

#[kingbase运维之奇怪的现象] ##奇怪的现象 某银行数据中心应用反馈&#xff0c;业务接口日志记录了很多执行慢的SQL&#xff0c;出现的时间是随机的&#xff0c;单独在数据库客户端工具执行会很快返回结果。根据之前的经验推断是业务代码传入的参数类型与数据库表结构字段定义…

HDD-FAT32 ZIP-FAT32 HDD-FAT16 ZIP-FAT16 HDD-NTFS

FAT32、FAT16指的是分区格式&#xff0c; FAT16单个文件最大2G FAT32单个文件最大4G NTFS单个文件大于4G HDD是硬盘启动 ZIP是软盘启动 U盘选HDD HDD-NTFS

buuctf crypto 【还原大师】解题记录

1.打开题目就能直接看到密文 2.感觉爆破直接能解&#xff0c;试试爆破&#xff08;参考文章&#xff1a;[buuctf] crypto全解——前84道&#xff08;不建议直接抄flag&#xff09;_buuctf crypto_咸鱼壹号的博客-CSDN博客&#xff09; import hashlib k TASC?O3RJMV?WDJKX?…

建筑模板9层板和7层板的区别

建筑模板是建筑施工过程中不可或缺的一环&#xff0c;而在建筑模板的选择中&#xff0c;常见的有9层板和7层板两种选项。它们在结构、特性和应用方面存在一些区别。下面将详细探讨9层板和7层板之间的区别。 首先&#xff0c;9层板和7层板的名称源自其板材的层数。9层板由9层木片…

Docker容器技术实战-1

1.docker容器 docker就好比传统的货运集装箱 每个虚拟机都有独立的操作系统&#xff0c;互不干扰&#xff0c;在这个虚拟机里可以跑任何东西 如应用 文件系统随便装&#xff0c;通过Guest OS 做了一个完全隔离&#xff0c;所以安全性很好&#xff0c;互不影响 容器 没有虚拟化…

Tomcat配置ssl、jar包

Tomcat配置ssl 部署tomcat服务&#xff0c;项目做到用https访问&#xff0c;使用nginx去做&#xff0c;访问任意一个子网站&#xff0c;都是https 或者 医美项目需要 上传jdk 456 tomcat war包 [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/…

AI绘画:StableDiffusion实操教程-斗破苍穹-云韵-常服(附高清图下载)

前段时间我分享了StableDiffusion的非常完整的教程&#xff1a;“AI绘画&#xff1a;Stable Diffusion 终极宝典&#xff1a;从入门到精通 ” 不久前&#xff0c;我与大家分享了StableDiffusion的全面教程&#xff1a;“AI绘画&#xff1a;Stable Diffusion 终极宝典&#xff…

用Navicat备份Mysql演示系统数据库的时候出:Too Many Connections

今天用Navicat进行数据备份的时候&#xff0c;发现由于数据库连接数目过多导致连接锁定&#xff0c;这种情况在多人协同开发的场景中很常见。当然我这里也因为多个应用使用了数据库连接&#xff0c;所以出现了Too Many Connections。 可能是超过最大连接数了。 1、进入Navicat…

【JAVA-Day03】JDK安装与IntelliJ IDEA安装、配置环境变量

JDK安装与IntelliJ IDEA安装、配置环境变量 一、JDK 版本介绍1.1 JDK 版本选择JDK 8JDK 11JDK 16JDK 171.2 JDK 下载1.3 JDK 安装1.4 配置环境变量1.5 验证 JDK 安装 二、开发利器——IntelliJ IDEA 的安装2.1 IntelliJ IDEA下载2.2 IntelliJ IDEA安装2.3 IntelliJ IDEA启动2.4…

编译原理:编译原理简明教程知识点梳理(应对考试版)

前言 姜老师是一个好老师&#xff0c;编译原理没有过是我的问题&#xff0c;我爱姜老师。 写这篇博客涉及到好多符号&#xff0c;可以参考这篇文章latex数学公式详细教程 因为打字过于麻烦&#xff0c;很多内容用平板的手写截图&#xff0c;还有电脑截图替代&#xff0c;不太习…

【刷题篇】贪心算法(一)

文章目录 分割平衡字符串买卖股票的最佳时机Ⅱ跳跃游戏钱币找零 分割平衡字符串 class Solution { public:int balancedStringSplit(string s) {int lens.size();int cnt0;int balance0;for(int i0;i<len;i){if(s[i]R){balance--;}else{balance;}if(balance0){cnt;}}return …