您的位置 首页 java

手写数据库连接池你还不会?废话少说,直接上代码

前言

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

废话少说,直接上代码!

 package com.huwc.dataSource;

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

/**
 * 对 Connection对象 的代理,主要作用为拦截connection的 close 方法
 */public class ConnectionProxy implements InvocationHandler {
    //真实的连接
    private Connection realConnection ;
    //代理的连接
    private Connection proxyConnection ;
    //数据源
    private HuwcDataSource dataSource ;

    //这是一个构造器
    public ConnectionProxy(Connection realConnection, HuwcDataSource dataSource) {
        this.realConnection = realConnection;
        this.dataSource = dataSource;
        //生成代理的Connection
        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 DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(HuwcDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        //拦截连接关闭的方法,对其进行扩展处理
        if(methodName.equalsIgnoreCase("close")){
             synchronized  (dataSource.getMonitor()){
                //活动连接list中remove这个ConnectionProxy
                dataSource.getActiveConnections().remove(this);
                //如果空闲连接list中的数量没有达到 阈值 ,则装入空间连接list,并notifyAll
                if(dataSource.getIdleConnections().size() < dataSource.getMaxIdleConnectionsCount()){
                    dataSource.getIdleConnections().add(this);
                    dataSource.getMonitor().notifyAll();
                }else{
                    //否则,直接关闭这个Connection
                    realConnection.close();
                }
            }
        }else{
            return method.invoke(realConnection, args) ;
        }
        return null;
    }
}  
 package com.huwc.dataSource;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * 给与DataSource接口中一些方法默认实现(就是不实现)
 */public abstract class HuwcAbstractDataSource implements DataSource {
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    public void setLoginTimeout(int seconds) throws SQLException {

    }

    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}  

 package com.huwc.dataSource;

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

public class HuwcDataSource extends HuwcAbstractDataSource {
    //空闲的连接
    private List<ConnectionProxy> idleConnections = new ArrayList<>();

    //活动的连接
    private List<ConnectionProxy> activeConnections = new ArrayList<>();

    //是否为本数据源第一次获取连接标志
    private boolean firstFlag = true ;
    //最小的空闲连接数
    private Integer minIdleConnectionsCount = 2;
    //最大的空闲连接数
    private Integer maxIdleConnectionsCount = 5;
    //最大的活动连接数
    private Integer maxActiveConnectionsCount = 10;
    //获取连接的最大的等待时间(毫秒)
    private Integer maxWaitToTimeOut = 30000;

    private String url;

    private String driver;

    private String user;

    private String password;

    private Object monitor = new Object();

    public boolean isFirstFlag() {
        return firstFlag;
    }

    public void setFirstFlag(boolean firstFlag) {
        this.firstFlag = firstFlag;
    }

    public List<ConnectionProxy> getIdleConnections() {
        return idleConnections;
    }

    public void setIdleConnections(List<ConnectionProxy> idleConnections) {
        this.idleConnections = idleConnections;
    }

    public List<ConnectionProxy> getActiveConnections() {
        return activeConnections;
    }

    public void setActiveConnections(List<ConnectionProxy> activeConnections) {
        this.activeConnections = activeConnections;
    }

    public Integer getMaxIdleConnectionsCount() {
        return maxIdleConnectionsCount;
    }

    public void setMaxIdleConnectionsCount(Integer maxIdleConnectionsCount) {
        this.maxIdleConnectionsCount = maxIdleConnectionsCount;
    }

    public Integer getMaxActiveConnectionsCount() {
        return maxActiveConnectionsCount;
    }

    public void setMaxActiveConnectionsCount(Integer maxActiveConnectionsCount) {
        this.maxActiveConnectionsCount = maxActiveConnectionsCount;
    }

    public Integer getMaxWaitToTimeOut() {
        return maxWaitToTimeOut;
    }

    public void setMaxWaitToTimeOut(Integer maxWaitToTimeOut) {
        this.maxWaitToTimeOut = maxWaitToTimeOut;
    }



    public Object getMonitor() {
        return monitor;
    }

    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 getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

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

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

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

    private Connection doGetConnection(String username, String password) throws SQLException {
        while(true) {
            synchronized (monitor) {
                //如果是本数据源第一次获取连接,那么首先进行init操作
                if(firstFlag)
                    init();
                //首先从空闲连接list中获取
                if (idleConnections.size() > 0) {
                    return idleConnections.remove(0).getProxyConnection();
                } else {//空闲连接list中如果没有连接的情况
                    //如果活动连接list的数量还没有达到阈值
                    if (maxActiveConnectionsCount > activeConnections.size()) {
                        //获取一个真实的Connection,并且封装为ConnectionProxy,装入活动连接list
                        ConnectionProxy connectionProxy = new ConnectionProxy(DriverManager.getConnection(url, user, password), this);
                        activeConnections.add(connectionProxy);
                        return connectionProxy.getProxyConnection();
                    } else {
                        //如果活动连接list的数量已经达到了阈值
                        //等待超时时间,并等待被唤醒
                        try {
                            monitor.wait(maxWaitToTimeOut);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
                }
            }
        }
        return null ;
    }

    private void init() {
        //首先进行锁定处理
        firstFlag = false;
        for(int i=0;i<minIdleConnectionsCount;i++){
            try {
                ConnectionProxy connectionProxy = new ConnectionProxy(DriverManager.getConnection(url, user, password), this);
                this.idleConnections.add(connectionProxy);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}  

总结:

通过jdk动态代理,给Connection对象生成一个代理对象,主要目的为拦截connection的close方法,不要直接进行connection的关闭,而是在DataSource中的活动连接集合和空闲连接集合进行转换。真实的Connection依然是通过DirverManager类来创建。

文章来源:智云一二三科技

文章标题:手写数据库连接池你还不会?废话少说,直接上代码

文章地址:https://www.zhihuclub.com/186044.shtml

关于作者: 智云科技

热门文章

网站地图