用JAVA 实现一个简版数据库连接池

在JAVA工程师的面试当中,数据库连接池的实现,肯定也是多线程等待超时模式的一个重要实现案例,通过网上的查阅,对数据连接池有了一定的了解,然后就自己写了一个简陋版,以供理解。

下面贴出代码:

1.创建数据库连接的驱动类,在真实环境中有数据库厂商提供驱动包。如mysql:mysql-connectorxxxx.jar

ConnectDriver(通过动态代理,对commit方法进行装饰):


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.concurrent.TimeUnit;

public class ConnectionDriver {

    static  class ConnectionHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            if(method.getName().equals("commit")){
                System.out.println("I am commit!!!");
                TimeUnit.MILLISECONDS.sleep(100);
            }
            return null;
        }
    }


    public static final Connection createConnection(){

         return    (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),new Class<?>[]{ Connection.class},new ConnectionHandler());

    }


}
2.数据连接池类(重要)。 我用过的有Pop3数据库连接池。

import java.sql.Connection;
import java.util.LinkedList;

public class MyDatabaseConnectPool {


    private static  final  int DEFAULT_SIZE=20;

    private static  final int MINSIZE=1;

    private static  final int MAXSIZE=100;


    //数据链接队列
    private LinkedList<Connection> connectionList=new LinkedList<>();


    //无参数构造
    public MyDatabaseConnectPool() {

        for(int i=0;i<DEFAULT_SIZE;++i){
            connectionList.add(ConnectionDriver.createConnection());
        }
    }



    //初始化连接池
    public MyDatabaseConnectPool(int initialSize) {



        if(initialSize>0){

            initialSize=initialSize<MINSIZE? MINSIZE:initialSize;
            initialSize=initialSize>MAXSIZE ? MAXSIZE:initialSize;


            for(int i=0;i<initialSize;++i){
                connectionList.add(ConnectionDriver.createConnection());
            }


        }else{
            throw new Error("initialSize must >0");
        }
    }

    public  void releaseConnection(Connection connection){

        if(connection!=null){

            synchronized (connectionList){
                //将空闲链接放入队列
                connectionList.addLast(connection);

                //通知其他等待的线程 有可用的链
                connectionList.notifyAll();
            }
        }

    }


    //获取链接函数
    public Connection getConnection(long mills) throws InterruptedException {

        //获取队列的锁
        synchronized (connectionList){

            if(mills<=0){

                while (connectionList.isEmpty()){

                    try {
                        connectionList.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                return  connectionList.removeFirst();

            }else{

                //进行超时等待获取链接

                long futrer_time=System.currentTimeMillis()+mills;

                long remain_time=mills;

                while (remain_time>0 && connectionList.isEmpty()){

                    connectionList.wait(remain_time);

                    //先等待后再获取剩余时间
                    remain_time=futrer_time-System.currentTimeMillis();
                }

                Connection connection=null;

                //如果此时队列不为空,获取链接
                if(!connectionList.isEmpty()){
                    connection=connectionList.removeFirst();
                }

                return  connection;
            }

        }

    }



}


分析:此处的队列使用LinkedList ,是为了使用链表增删节点性能较好。还可以使用下面的方法:

 connectionList.addLast(connection);   

 connectionList.removeFirst();

3.测试类:

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class Test {

    static MyDatabaseConnectPool pool = null;

    //设定两个闭关锁  一个用于开启线程活动        一个用于监控所有线程的工作完成状态
    static CountDownLatch start = new CountDownLatch(1);

    static CountDownLatch end;


    public static void main(String[] args) {

        System.out.println("我们开始运行!!!!");

        pool=new MyDatabaseConnectPool(-5);
        int thread_count=10;
        int count=20;

        end=new CountDownLatch(thread_count);
        AtomicInteger success_count=new AtomicInteger(0);
        AtomicInteger faile_count=new AtomicInteger(0);


        //开启多个线程
        for(int i=0;i<thread_count;++i){
            new MyConnectUser(count,success_count,faile_count).start();
        }

        //发出  可以获取链接 的命令
        start.countDown();

        try {
            //此处锁住 等待所有线程完成工作
            end.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //打印各个指标

        System.out.println("The total try times :"+thread_count*count);
        System.out.println("The total success times: "+success_count);
        System.out.println("The totla faile times :"+faile_count);


    }




    private static class MyConnectUser extends Thread {

        //线程内获取次数
        int count;

        //分别用来统计 成功/失败 获取次数
        AtomicInteger success_count;
        AtomicInteger faile_cout;


        public MyConnectUser(int count, AtomicInteger success_count, AtomicInteger faile_cout) {

            this.count = count;
            this.success_count = success_count;
            this.faile_cout = faile_cout;

        }

        @Override
        public void run() {

            try {
                start.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            while (count>0){

                try {
                    //尝试获取链接
                    Connection connection= pool.getConnection(50);

                    if(connection!=null) {

                        try {
                            //模拟真实使用链接
                            connection.createStatement();
                            connection.commit();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }finally {
                            //成功次数加1
                            success_count.incrementAndGet();
                            //释放链接
                            pool.releaseConnection(connection);
                        }

                    }else{
                        //失败次数加1
                        faile_cout.incrementAndGet();
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //线程内尝试获取次数减一
                    count--;

                }
            }
            //告诉end 我这个线程的工作完成
            end.countDown();
        }
    }


}
总结:这只是我对数据库连接池的理解和简单实现,真是的数据库连接池肯定是要复杂的多。如果有出错的地方请各位在评论处指出。

 
 




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值