模仿连接池原理(回收连接,而不是释放连接)

264 阅读2分钟

由c3p0或者druid创建出来的连接池,获取连接和操做对象后,调用close方法,不是真正的关闭

这是我的配置文件,初始化连接数是3,最大连接数是5

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/demobase?useSSL=false&serverTimezone=GMT
    username=root
    password=dong
    #//属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wall
    filters=stat
    initialSize=3
    maxActive=5
    maxWait=60000

这是Druid连接池工具 主要用来演示获取连接,具体内容不写太多

    public class DruidUtil {
    static DataSource dataSource;
    static Properties properties = new Properties();
    static {
        InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("durid.properties");
        try {
            properties.load(is);
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void close(Connection conn, Statement ps, ResultSet rs){
        .......
    }
}

开始实验

 public class Test2 {
    public static void main(String[] args) throws SQLException {
        Connection connection1 = DruidUtil.getConnection();
        System.out.println("1: "+connection1);
        Connection connection2 = DruidUtil.getConnection();
        System.out.println("2: "+connection2);
        Connection connection3 = DruidUtil.getConnection();
        System.out.println("3: "+connection3);
        Connection connection4 = DruidUtil.getConnection();
        System.out.println("4: "+connection4);
        Connection connection5 = DruidUtil.getConnection();
        System.out.println("5: "+connection5);
        Connection connection6 = DruidUtil.getConnection();
        System.out.println("6: "+connection6);
    }
}

由于最大连接数是5,所以第6个连接一直处于等待状态,最终打印结果如下:

在connection3,connection后加上

cconnection3.close();

cconnection4.close();

打印结果变为:

可以看到connection 3,4,5的地址是一样的,原因是:

connection3关闭后,被回收,connection4获取连接,获取的是上一次被回收的,connection4关闭后,connection5又获取了这个连接

这就是连接池的回收机制


模仿连接池的原理

1-先找到一个实现了Connection接口的类,我选用的是ConnectionImpl类

2-创建一个代理类

public class ConnProxy extends ConnectionImpl {
    private static Connection connection;

    public ConnProxy(Connection connection){
        this.connection = connection;
    }
    //这里重写了close方法。 
    //用该类创建的connection对象,调用的close方法就是我们重写的close方法
    //其他的connection操做,都交给ConnectionImpl来实现
    @Override
    public void close() throws SQLException {
        if (DruidUtil.totalCount>3){
            DruidUtil.totalCount--;
            try {
                this.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }else {
            DruidUtil.connList.add(this);
        }
    }
}

3-修改Druid工具类

public class DruidUtil {
    private static DataSource dataSource;
    private static Properties properties = new Properties();

    public static List<Connection> connList = new ArrayList<>();
    //记录初始化连接数
    static int totalCount = 3;
    //设置最大连接数
    static int maxCount = 5;
    static {
        try {
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("durid.properties");
            properties.load(is);
            dataSource = DruidDataSourceFactory.createDataSource(properties);
            Connection conn1 = dataSource.getConnection();
            Connection conn2= dataSource.getConnection();
            Connection conn3 = dataSource.getConnection();
            //用代理类创建Connection对象
            Connection connProxy1 = new ConnProxy(conn1);
            Connection connProxy2 = new ConnProxy(conn2);
            Connection connProxy3 = new ConnProxy(conn3);
            connList.add(connProxy1);
            connList.add(connProxy2);
            connList.add(connProxy3);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        if (connList.size()>0){
            return connList.remove(0);
        }else if (totalCount<maxCount){
            totalCount++;
            return dataSource.getConnection();
        }
        return null;
    }

    public static DataSource getDataSource(){
        return dataSource;
    }

4-测试

    public class DruidAndProxy {
        public static void main(String[] args) throws SQLException {
            Connection conn1 = DruidUtil.getConnection();
            System.out.println(conn1);
            Connection conn2 = DruidUtil.getConnection();
            System.out.println(conn2);
            Connection conn3 = DruidUtil.getConnection();
            System.out.println(conn3);
            conn3.close();
            Connection conn4 = DruidUtil.getConnection();
            System.out.println(conn4);
            conn2.close();
            Connection conn5 = DruidUtil.getConnection();
            System.out.println(conn5);
            Connection conn6 = DruidUtil.getConnection();
            System.out.println(conn6);
        }
    }

connection 结果:

connection4 用的是 connection3 用过的 connection

connection5 用的是 connection2 用过的 connection

connection6 用的是 临时创建的connection对象

注释掉connection3和2的close方法后,结果如下: