手写数据库连接池

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

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

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

手写数据库连接池_第1张图片

数据库连接池技术方案:

1.C3P0

2.DBCP

3.Proxool

4.Tomcat jdbc Oppl

5.BoneCP

6.Druid

7.HikariCP

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

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

新建个空项目

手写数据库连接池_第2张图片

手写数据库连接池_第3张图片

手写数据库连接池_第4张图片

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

设置下maven和encoding

新建模块

手写数据库连接池_第5张图片

手写数据库连接池_第6张图片

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

手写数据库连接池_第7张图片

自定义一个接口

手写数据库连接池_第8张图片

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

手写数据库连接池_第9张图片

手写数据库连接池_第10张图片

这样基础结构就有了

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;
 //最大的连接数量
    private int poolMaxActiveConnection=10;

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

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

    public int getPoolMaxActiveConnection() {
        return poolMaxActiveConnection;
    }

    public void setPoolMaxActiveConnection(int poolMaxActiveConnection) {
        this.poolMaxActiveConnection = poolMaxActiveConnection;
    }

    public int getPoolMaxIdIeConnection() {
        return poolMaxIdIeConnection;
    }

    public void setPoolMaxIdIeConnection(int poolMaxIdIeConnection) {
        this.poolMaxIdIeConnection = poolMaxIdIeConnection;
    }

    public int getPoolTimeToWait() {
        return poolTimeToWait;
    }

    public void setPoolTimeToWait(int poolTimeToWait) {
        this.poolTimeToWait = poolTimeToWait;
    }

    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 idleConnections=new ArrayList<>();

    //激活的连接池
    private final List 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()

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

手写数据库连接池_第11张图片

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

下面测试自己写的连接池

新建模块  引入依赖

手写数据库连接池_第12张图片

手写数据库连接池_第13张图片

不想玩了

你可能感兴趣的:(数据库,mybatis,学习)