JDBC连接池原理及分析

Posted 开源java学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC连接池原理及分析相关的知识,希望对你有一定的参考价值。

一、.背景介绍 

什么是连接池 

1)连接池,首先从字面意思理解,这是一个偏正短语,左偏右正,重点在池这个字上。池(Pool)技术在一定程度上可以明显优化服务器应用程序的性能,提高程序执行效率和降低系统资源开销。这里所说的池是一种广义上的池,比如数据库连接池、线程池、内存池、对象池等。其中,对象池可以看成保存对象的容器,在进程初始化时创建一定数量的对象。需要时直接从池中取出一个空闲对象,用完后并不直接释放掉对象,而是再放到对象池中以方便下一次对象请求可以直接复用。其他几种池的设计思想也是如此,池技术的优势是,可以消除对象创建所带来的延迟,从而提高系统的性能。 

2)数据库连接”是一种稀缺的资源,建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,不是关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。 

这就好比是要从A城市去B城市,如果提前修了一条公路(类似我们这块连接池里的连接这个资源)我们要去就可以直接开车去了,若果没有公路,我们还得现修公路,这将非常耗时耗力。向下图中一样,我们连接数据库的时候先到连接池去找连接资源,如果有我们就直接使用,如果没有或者不够我们才创建一个连接。 

二、知识剖析 

2.1连接池关键问题剖分析: 

1)并发问题 

为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如: 

public synchronized Connection getConnection() 

2)多数据库服务器和多用户 

3)事务处理 

我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-ALL-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。 

在Java语言中,Connection类本身提供了对事务的支持,可以通过设置Connection的AutoCommit属性为false,然后显式的调用commit或rollback方法来实现。但要高效的进行Connection复用,就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现,这种方法可以大大降低事务管理的复杂性。 

4)连接池的分配与释放 

连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。 

5)对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxConn),如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout,则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。 

如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。 

2.2连接池的实现: 

 1)连接池模型——连接池类 

 本文讨论的连接池包括一个连接池类(DBConnectionPool)和一个连接池管理类(DBConnetionPoolManager)。连接池类是对某一数据库所有连接的“缓冲池”,主要实现以下功能:①从连接池获取或创建可用连接;②使用完毕之后,把连接返还给连接池;③在系统关闭前,断开所有连接并释放连接占用的系统资源;④还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。 

 2)连接池模型——连接池管理类 

 连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。其主要用于对多个连接池对象的管理,具有以下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,创建连接池对象;③为方便管理多个连接池对象,为每一个连接池对象取一个名字,实现连接池名字与其实例之间的映射;④跟踪客户使用连接情况,以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理,如系统需要连接不同的数据库,或连接相同的数据库但由于安全性问题,需要不同的用户使用不同的名称和密码。 

2.3数据库的连接 

1)加载数据库的驱动 

2)通过JCBC建立数据库连接 

3)访问数据库,执行sql语句 

4)断开数据库连接,释放资源 

2.4实现连接池的步骤 

1)编写class用作连接池 

2)在class构造器里一次性创建若干个连接,将连接保存造LinkedList中 

3)实现getConnection从LinkList中返回一个连接 

4)操作完后,提供将连接放回连接池中方法。 

2.5连接池测试 

1)从刚刚写的连接池里面获取连接 

2)进行数据库操作 

3)操作完成后,把连接返回给连接池 

4)具体看编码实战 

三、常见问题 

1)无法获取数据库连接 

2)运行一会报错了 

四、解决方案解决方案 

4.1无法获取数据库连接 

a)无法获取数据库连接的原因,最简单的就是没添加依赖 

b) 其次是驱动用户名密码等写错了 

c) 也有可能没启动数据库服务或者没开放连接权限 

d) 还有一种情况就是,读取配置文件的时候出错,导致连接池初始化失败 

4.2运行一会儿报错了 

a)报错,可能是因为断网了,一直连不上数据库,所以报错了 

b)或者是最大连接数用完了,还在请求创建连接 

五、编码实战 

这是连接池池的程序


package com.ossjk.datasource;


import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.util.LinkedList;


public class MyDataSource {

    //LinkedList集合,存储连接的容器---连接池

    private LinkedList<Connection> dataSources = new LinkedList();

    //初始化连接数量

    public MyDataSource() {

        //一次性创建10个连接

        for(int i = 0; i < 10; i++) {

            try {

                //1、装载驱动对象

                Class.forName("com.mysql.jdbc.Driver");

                //2、通过JDBC建立数据库连接

                Connection con =DriverManager.getConnection(

                        "jdbc:mysql://localhost:3306/practice?useSSL=false", "root", "123456");

                //3、将连接加入连接池中

                dataSources.add(con);

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }


    public Connection getConnection() throws SQLException {

        //取出连接池中一个连接

        final Connection conn = dataSources.removeFirst(); // 获取第一个连接给Connection,把剩下的连接返回给LinkedList集合

        System.out.println("执行数据库的操作时,连接池内剩余连接个数:"+dataSources.size());//输出集合里面剩下的连接的个数

        return conn;

    }


    public void releaseConnection(Connection conn) {

        //把连接返还给连接池

        dataSources.add(conn);

        System.out.println("数据库操作完成时,连接池剩余连接个数:"+dataSources.size());//输出集合里面剩下的连接的个数

    }

}


这是测试程序


package com.ossjk.datasource;


import java.sql.Connection;

import java.sql.ResultSet;

import java.sql.Statement;


public class DataSourceDemo {

        public static void main(String[] args) throws Exception{

            //1、使用连接池建立数据库连接

            MyDataSource myDataSource = new MyDataSource();

            Connection conn =myDataSource.getConnection();

            //2、创建状态

            Statement state =conn.createStatement();

            //3、查询数据库并返回结果

            ResultSet result =state.executeQuery("select * from user where id=5");

            //4、输出查询结果

            while(result.next()){

                System.out.println(result.getString("name"));

            }

            //5、断开数据库连接

            result.close();

            state.close();

//        Connection connection=myDataSource.getConnection();

            //6、归还数据库连接给连接池

            myDataSource.releaseConnection(conn);

        }

    }


六、扩展思考 

1 连接池有几种? 

这个博客对几个常用的连接池的性能分析。

DBCP 、C3P0、BoneCP、Proxool、DDConnectionBroker、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。 

2 连接池有什么好处 

连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。 

共享资源,连接池的使用解决了资源频繁分配、释放所造成的问题的。提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。 

3 如何选取连接池 

简单的说需要根据所要处理的业务量进行测试后选择合适的连接池,这牵扯到了技术选型。 

以上是关于JDBC连接池原理及分析的主要内容,如果未能解决你的问题,请参考以下文章

DBCP连接池原理分析

jdbc之连接池

DBCP数据库连接池原理分析

搞软件开发,请你来谈谈数据库连接池的原理吧

数据库连接池原理分析及模拟实现

数据库连接池原理及应用