java 数据库连接池的简单实现

一、背景

        数据库连接池的实现,在一般的Javaweb项目中,持久层框架基本已经实现好,开发者只需要关心增删改查操作即可。不过公司项目的需求多样性和复杂性是很难预料的,我目前做的项目我认为需要自己来做一个简单的线程池来维护。我的项目需求是这样的:前端通过传入一个标识:code,后端通过code查询出一条数据,此条数据中包括了另一个数据库的 链接方式,包括IP,username,password等信息,而此时需要通过链接这个数据库的表数据来返回给前端。 此需求分析来看:1、数据库,用户名,密码是动态的,无法提前创建。2、数据库,用户名,密码有可能都一样,只是查询的表不一样,但由于本身这些数据都是动态给的,所以要考虑后续突然增加了一个数据库的情况。这种需求的情况下我自己写了一个数据库连接池自己使用,当然此篇文章只是说明数据库连接池的实现和我那个需求无关。

二、为什么要使用数据库连接池

        连接数据库首先需要建立连接Connection,之后操作一系列的增删改查的操作,最后close掉connection等一些资源。而在建立连接和关闭连接的操作是需要同远程服务器的数据库建立关系,比较消耗时间,如果频繁创建和关闭会导致程序整体运行速度下降。此时就引来了连接池,数据库连接池是提前创建好一定的connection链接存到集合,当使用时直接从这个地方去取出,当close时,不是真正的关闭,而是将connection归还给集合中。这样就将创建链接的时间放在数据库连接池第一次创建的阶段,一劳永逸的效果。

三、数据库连接词的实现

       连接池的实现其实主要实现两部分:1、创建连接集合存储connection连接。2、close关闭资源时,转换为归还给集合而不是真正close。

3.1  连接池集合创建。

private static LinkedList<Connection> connectionList = new LinkedList<>();

static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for (int i = 0; i < 10 ; i++) {
                Connection con= DriverManager.getConnection(url,username,password);
                connectionList.add(con);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

此处创建了大小为10的连接池,其实就是循环创建连接然后存到集合中去。

3.2  close时,转换为归还给集合而不是真正close,此处需要用代理来处理

 public Connection getConnection() throws SQLException {
        if(connectionList.size()>0){
            final Connection connection = connectionList.removeFirst();
            Connection conn = (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if(!method.getName().equals("close")){
                        return method.invoke(connection, args);
                    }else{
                        connectionList.add(connection);
                    }
                    return null;
                }
            });
            return conn ;
        }else{
            throw new RuntimeException("数据库繁忙,稍后再试!");
        }
    }

利用代理判断是否调用了close方法,如果调用了,就归还给集合,此处要注意,使用时是取出一个connection,也就是集合要少一个connection,而不是获取一个connection。

3.3 两个关键的地方写完,其实简单的连接池也差不多完事了,下面附完整代码

package com.hgt.datashare.utils;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;

/**
 * @author WYH
 */
public class JdbcPool implements DataSource {

    private static LinkedList<Connection> connectionList = new LinkedList<>();

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for (int i = 0; i < 10 ; i++) {
                Connection con= DriverManager.getConnection(url,username,password);
                connectionList.add(con);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    

    @Override
    public Connection getConnection() throws SQLException {
        if(connectionList.size()>0){
            final Connection connection = connectionList.removeFirst();
            Connection conn = (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if(!method.getName().equals("close")){
                        return method.invoke(connection, args);
                    }else{
                        connectionList.add(connection);
                    }
                    return null;
                }
            });
            return conn;
        }else{
            throw new RuntimeException("数据库繁忙,稍后再试!");
        }
    }

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

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

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

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

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

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

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

此处要注意的是,连接池类需要实现DataSource,此处只是一个连接池的创建,之后的使用读者可以创建一个utils工具来调取,同时写好关闭资源的操作,这里就不再列出。

猜你喜欢

转载自blog.csdn.net/qq_34297563/article/details/89308813