连接池_连接池参数 - CSDN
连接池 订阅
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。 展开全文
连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。
信息
性    质
创建和管理连接的缓冲池的技术
外文名
Connection Pool
中文名
连接池
连接池好处
这种连接“汇集”起来的技术基于这样的一个事实:对于大多数应用程序,当它们正在处理通常需要数毫秒完成的事务时,仅需要能够访问JDBC连接的 1 个线程。当不处理事务时,这个连接就会闲置。相反,连接池允许闲置的连接被其它需要的线程使用。事实上,当一个线程需要用 JDBC 对一个 GBase 或其它数据库操作时,它从池中请求一个连接。当这个线程使用完了这个连接,将它返回到连接池中,这样这就可以被其它想使用它的线程使用。当连接从池中“借出”,它被请求它的线程专有地使用。从编程的角度来看,这和用户的线程每当需要一个 JDBC 连接的时候调用DriverManager.getConnection() 是一样的,采用连接池技术,可通过使用新的或已有的连接结束线程。连接池可以极大的改善用户的 Java 应用程序的性能,同时减少全部资源的使用。连接池主要的优点有:减少连接创建时间虽然与其它数据库相比 GBase 提供了较为快速连接功能,但是创建新的 JDBC 连接仍会招致网络和 JDBC 驱动的开销。如果这类连接是“循环”使用的,使用该方式这些花销就可避免。简化的编程模式当使用连接池时,每一个单独的线程能够像创建了一个自己的 JDBC 连接一样操作,允许用户直接使用JDBC编程技术。受控的资源使用如果用户不使用连接池,而是每当线程需要时创建一个新的连接,那么用户的应用程序的资源使用会产生非常大的浪费并且可能会导致高负载下的异常发生。注意,每个连到 GBase 的连接在客户端和服务器端都有花销(内存,CPU,上下文切换等等)。每个连接均会对应用程序和 GBase 服务器的可用资源带来一定的限制。不管这些连接是否在做有用的工作,仍将使用这些资源中的相当一部分。连接池能够使性能最大化,同时还能将资源利用控制在一定的水平之下,如果超过该水平,应用程序将崩溃而不仅仅是变慢。
收起全文
精华内容
参与话题
  • 谈谈数据库连接池的原理

    万次阅读 多人点赞 2013-11-08 09:13:09
    这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。

    谈谈数据库连接池的原理

                                                                                                                                                                             帅宏军

         这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。

    一.早期我们怎么进行数据库操作

           1.原理:一般来说,java应用程序访问数据库的过程是:

       ①装载数据库驱动程序;

       ②通过jdbc建立数据库连接;

       ③访问数据库,执行sql语句;

       ④断开数据库连接。

           2.代码 

           // 查询所有用户

           Public void FindAllUsers(){
                  //1、装载sqlserver驱动对象
                  DriverManager.registerDriver(new SQLServerDriver());             
                  //2、通过JDBC建立数据库连接
                  Connection con =DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");            
                  //3、创建状态
                  Statement state =con.createStatement();           
                  //4、查询数据库并返回结果
                  ResultSet result =state.executeQuery("select * from users");           
                  //5、输出查询结果
                  while(result.next()){
                         System.out.println(result.getString("email"));
                  }            
                  //6、断开数据库连接
                  result.close();
                  state.close();
                  con.close();
            }

    3.分析

           程序开发过程中,存在很多问题:首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

           上述的用户查询案例,如果同时有1000人访问,就会不断的有数据库连接、断开操作:

     

           通过上面的分析,我们可以看出来,“数据库连接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。原理如下:

    二. 技术演进出来的数据库连接池

           由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

           我们自己尝试开发一个连接池,来为上面的查询业务提供数据库连接服务:

           ①   编写class 实现DataSource 接口

           ②   class构造器一次性创建10个连接,将连接保存LinkedList

           ③   实现getConnection  LinkedList返回一个连接

           ④   提供将连接放回连接池中方法

     

           1、连接池代码       

        public class MyDataSource implements DataSource {
                  //链表 --- 实现栈结构
                  privateLinkedList<Connection> dataSources = new LinkedList<Connection>();
     
                  //初始化连接数量
                  publicMyDataSource() {
                         //一次性创建10个连接
                         for(int i = 0; i < 10; i++) {
                                try {
                                   //1、装载sqlserver驱动对象
                                   DriverManager.registerDriver(new SQLServerDriver());
                                   //2、通过JDBC建立数据库连接
                                   Connection con =DriverManager.getConnection(
                                      "jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer", "sa", "123");
                                   //3、将连接加入连接池中
                                   dataSources.add(con);
                                } catch (Exception e) {
                                   e.printStackTrace();
                                }
                         }
                  }
     
                  @Override
                  publicConnection getConnection() throws SQLException {
                         //取出连接池中一个连接
                         finalConnection conn = dataSources.removeFirst(); // 删除第一个连接返回
                         returnconn;
                  }
     
                  //将连接放回连接池
                  publicvoid releaseConnection(Connection conn) {
                         dataSources.add(conn);
                         }
           }


           2、使用连接池重构我们的用户查询函数       

           //查询所有用户
           Public void FindAllUsers(){
                  //1、使用连接池建立数据库连接
                  MyDataSource dataSource = new MyDataSource();
                  Connection conn =dataSource.getConnection();        
                  //2、创建状态
                  Statement state =con.createStatement();           
                  //3、查询数据库并返回结果
                  ResultSet result =state.executeQuery("select * from users");           
                  //4、输出查询结果
                  while(result.next()){
                         System.out.println(result.getString("email"));
                  }            
                  //5、断开数据库连接
                  result.close();
                  state.close();
                  //6、归还数据库连接给连接池
                  dataSource.releaseConnection(conn);
            }

           这就是数据库连接池的原理,它大大提供了数据库连接的利用率,减小了内存吞吐的开销。我们在开发过程中,就不需要再关心数据库连接的问题,自然有数据库连接池帮助我们处理,这回放心了吧。但连接池需要考虑的问题不仅仅如此,下面我们就看看还有哪些问题需要考虑。

    三.连接池还要考虑更多的问题

           1、并发问题

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

          publicsynchronized connection getconnection()

     

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

           对于大型的企业级应用,常常需要同时连接不同的数据库(如连接oraclesybase)。如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址等信息。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。

           对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。

     

           3、事务处理

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

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

     

           4、连接池的分配与释放

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

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

     

           5、连接池的配置与维护

           连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minconn)和最大连接数(maxconn)来控制连接池中的连接。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过反复测试,找到最佳点。

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

    四.实际开发中有成熟的开源连接池供我们使用

           理解了连接池的原理就可以了,没有必要什么都从头写一遍,那样会花费很多时间,并且性能及稳定性也不一定满足要求。事实上,已经存在很多流行的性能优良的第三方数据库连接池jar包供我们使用。如:

           1.Apache commons-dbcp 连接池

            下载:http://commons.apache.org/proper/commons-dbcp/

     

           2.c3p0 数据库连接池

            下载:http://sourceforge.net/projects/c3p0/

     

          网上有很多关于这些连接池的介绍文章,这里就不再进行展开。


    转载请注明出处:http://blog.csdn.net/shuaihj/article/details/14223015

    展开全文
  • 连接池详解

    千次阅读 2019-12-02 19:38:33
    数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来...

    对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

     

    为什么使用连接池

    连接,是我们的编程语言与数据库交互的一种方式。我们经常会听到这么一句话“数据库连接很昂贵“。

    有人接受这种说法,却不知道它的真正含义。因此,下面通过实例解释它究竟是什么。

     

    下面是Mysql数据库创建连接的的一段代码:

     

     

    String connUrl ="jdbc:mysql://your.database.domain/yourDBname";
    Class.forName("com.mysql.jdbc.Driver");
    Connection con =DriverManager.getConnection (connUrl);

    当我们创建了一个Connection对象,它在内部都执行了什么:

     

     

    1.“DriverManager”检查并注册驱动程序;

    2.“com.mysql.jdbc.Driver”就是我们注册了的驱动程序,它会在驱动程序类中调用“connect(url…)”方法。

    3.com.mysql.jdbc.Driver的connect方法根据我们请求的“connUrl”,创建一个“Socket连接”,连接到IP为“your.database.domain”,默认端口3306的数据库。

    4.创建的Socket连接将被用来查询我们指定的数据库,并最终让程序返回得到一个结果。

    简单的获取一个连接,系统却要在背后做很多消耗资源的事情,大多时候,创建连接的时间比执行sql语句的时间还要长。

     

    传统的获取连接方式如下图所示:

     

    用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。

     

    采用连接池技术后的过程如下:

     

    数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

     

    需要注意的问题

    1、并发问题

    为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为各个语言自身提供了对并发管理的支持像java,c#等等,使用synchronized(java)、lock(C#)关键字即可确保线程是同步的。

    2、事务处理

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

    我们知道当2个线程公用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有2个线程都在进行事务操作而引起的。为此我们可以使用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。

    3、连接池的分配与释放

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

    对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他(如何能找到最合适的连接文章将在关键议题中指出);如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理。

    4、连接池的配置与维护

    连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConnection)和最大连接数(maxConnection)等参数来控制连接池中的连接。比方说,最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求上得到。

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

     

    Tomcat连接池

    Tomcat默认使用的是DBCP数据库连接池,其实从本质上讲,Tomcat是利用Apache Commons DBCP来实现的,只不过把特定的功能集成到了tomcat-dbcp.jar包中。

    使用法法如下:

    步骤1:

    在Tomcat中Context.xml中添加

     

    <!--  path表示站点的访问方式 -->
    <!--    例:http://localhost:8080/test 配置为/test -->
    <!-- docBase="fileLocation" 应用存储的实际路径,没有的话则从webapps目录找 -->
    <!-- Context标签内的这些属性都可以省略不写,使用默认的设置 -->
    <Context path="/TomcatDbPools" docBase="TomcatDbPools" debug="0" reloadable="true">
        		<!--     使用DBCP配置的数据源        -->
    <Resource 
    <!-- 指定资源池的Resource的JNDI的名字,就是给连接池起的名字 -->
           name="jdbc/mysql_connect"  
    <!-- 管理权限,指定管理Resource的Manager,可以是Container或Application -->
           auth="Container"          
    <!--指出Resource所属的类名,是什么类型的数据源-->
           type="javax.sql.DataSource"  
    <!-- 数据库驱动类 -->
           driverClassName="com.mysql.jdbc.Driver"  
    <!-- 数据库连接url-->
           url=" jdbc:mysql://localhost:3306/test"  
    <!-- 数据库用户名 -->
           username="admin"  
    <!-- 数据库密码 -->
           password="123456"  
    <!-- 连接池最大激活的连接数,设为0表示无限制-->
           maxActive="100"  
    <!-- 连接池中最多可空闲的连接数 -->
           maxIdle="30"  
    <!-- 为连接最大的等待时间,单位毫秒,如果超过此时间将接到异常。设为-1表示无限制-->
           maxWait="10000" /> 
    </context>
    
    注:还可以用minIdle配置连接池中最少空闲maxIdle个连接,用initialSize配置初始化连接数目。可同时配置多个数据源。

     

     

     

    如果在Tomcat的server.xml文件中配置数据源,有两种方法都可以实现:

    方法1:将上面的配置内容直接添加在<Host>节点下。

    方法2:在<GlobalNamingResources>节点下添加:

     

    <GlobalNamingResources>
    <!-- 这里的factory指的是该Resource 配置使用的是哪个数据源配置类,这里使用的是tomcat自带的标准数据源Resource配置类,-->
    <!-- 这个类也可以自己写,实现javax.naming.spi.ObjectFactory 接口即可。 -->
    <!-- 某些地方使用的commons-dbcp.jar中的org.apache.commons.dbcp.BasicDataSourceFactory,-->
    <!-- 如果使用这个就需把commons-dbcp.jar及其依赖的jar包,都放在tomcat的lib下,光放在工程的WEB-INF/lib下是不够的。  -->
    	<Resource 
    	name="mysql_connect"				
    	factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
    	maxActive="100" 
    	maxIdle="30" 
    	maxWait="10000" 
    	name="jdbc/TomcatDbPool1" 
    	password="123456" 
    	type="javax.sql.DataSource" 
    	url="jdbc:mysql://localhost:3306/test" 
    	username="root"/>             
    </GlobalNamingResources>

    然后在context.xml文件中的<Context></Context>节点中加入如下内容:

     

     

    <ResourceLink name="jdbc/mysql_connect" global="mysql_connect" type="javax.sql.DataSource"/>

    在server.xml中配置的数据源是全局的,所有项目都可以使用。全局的resource只是为了重用,方便所有该tomcat下的web工程的数据源管理,但如果你的tomcat不会同时加载多个web工程,也就是说一个tomcat只加载一个web工程时,是没有必要配置全局的resource的。

     

    此外,还需要将mysql的Java驱动类以及其他依赖包(如果有)放到tomcat的lib目录下。

     

    步骤2:

    在web.xml中,配置<resource-ref>元素以在web应用中引用JNDI资源。    

     

    <resource-ref>
          <!-- 对该资源的描述语言 -->
       <description> dbcpconnect</description>
          <!-- 引用的资源名,必须与Context.xml中的名字一致 -->
       <res-ref-name> jdbc/mysql_connect </res-ref-name>
          <!-- 资源类型 -->
      <res-type>javax.sql.DataSource</res-type>
          <!-- 管理权限 -->
       <res-auth>Container</res-auth>
    </resource-ref>
     

     

    步骤3:

    在Web应用中使用数据源

     

    //获得对数据源的引用:
    Context ctx =new InitialContext();
    //java:comp/env/是java中JNDI固定写法。
    DataSource ds =(DataSource) ctx.lookup("java:comp/env/jdbc/mysql_connect ");
    //获得数据库连接对象:
    Connection conn= ds.getConnection();
    //返回数据库连接到连接池:
    conn.close();
     

     

    DBCP连接池

    DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 文件:

    Commons-dbcp.jar:连接池的实现

    Commons-pool.jar:连接池实现的依赖库

    Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

     

    步骤1:

    在类目录下加入dbcp的配置文件:dbcp.properties

     

    #数据库驱动
    driverClassName=com.mysql.jdbc.Driver
    #数据库连接地址
    url=jdbc:mysql://localhost/test
    #用户名
    username=root
    #密码
    password=123456
    #连接池的最大数据库连接数。设为0表示无限制
    maxActive=30
    #最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连
    #接将被标记为不可用,然后被释放。设为0表示无限制
    maxIdle=10
    #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制
    maxWait=1000
    #超过removeAbandonedTimeout时间后,是否进行没用连接(废弃)的回收(默认为false,调整为true)
    removeAbandoned=true
    #超过时间限制,回收没有用(废弃)的连接(默认为 300秒)
    removeAbandonedTimeout=180

     

     

    步骤2:

    在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池:

     

    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    import javax.sql.DataSource;
    import org.apache.commons.dbcp.BasicDataSourceFactory;
     
          /**
         * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现
         * DBCP连接池就是java.sql.DataSource接口的一个具体实现
         */
    public classJdbcUtils_DBCP {
      
        private static DataSource ds = null;
        //在静态代码块中创建数据库连接池
        static{
            try{
                //加载dbcp.properties配置文件
                InputStream in =JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp.properties");
                Properties prop = new Properties();
                prop.load(in);
                //创建数据源
                ds =BasicDataSourceFactory.createDataSource(prop);
            }catch (Exception e) {
                throw newExceptionInInitializerError(e);
            }
        }
       
        //从数据源中获取数据库连接
        public static Connection getConnection()throws SQLException{
            //从数据源中获取数据库连接
            return ds.getConnection();
        }
       
        //释放连接
        public static void release(Connection conn){
              if(conn!=null){
                try{
                    //将Connection连接对象还给数据库连接池
                    conn.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
          }
     }
    }
     

     

    步骤3:

    在应用中获取连接

          

            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
            try{
                //获取数据库连接
                conn =JdbcUtils_DBCP.getConnection();
                ……
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                JdbcUtils_DBCP.release(conn);
            }

     

     

    C3P0连接池

    c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0一般是与Hibernate,Spring等框架一块使用的,当然也可以单独使用。

    dbcp没有自动回收空闲连接的功能,c3p0有自动回收空闲连接功能

    使用c3p0需要导入c3p0.jarmchange-commons-.jar,如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-pre1.jar。

     

    步骤1:

    在类目录下加入C3P0的配置文件:c3p0-config.xml

     

    <c3p0-config>
        
       <!--  C3P0的缺省(默认)配置,-->
       <!-- 如果在代码中“ComboPooledDataSourceds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源 -->
       
       <default-config>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/anysearch</property>
            <property name="user">root</property>
            <property name="password">123456</property>
                 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default:3 -->
            <property name="acquireIncrement">5</property>
                 <!--初始化的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3-->
            <property name="initialPoolSize">10</property>
                 <!--连接池中保留的最小连接数-->
            <property name="minPoolSize">5</property>
                 <!--连接池中保留的最大连接数。Default:15 -->
            <property name="maxPoolSize">20</property>
                 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
            <property name="acquireRetryAttempts">30</property>
                 <!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
            <property name="acquireRetryDelay">1000</property>
                 <!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
             <property name="autoCommitOnClose">false</property>
        </default-config>
        
        <!-- C3P0的命名配置,-->
        <!-- 如果在代码中“ComboPooledDataSourceds = new ComboPooledDataSource("MySQL");”这样写就表示使用的是name是MySQL的配置信息来创建数据源 -->
        
        <named-config name="MySQL">
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/test2</property>
            <property name="user">root</property>
            <property name="password">123456</property>
            <property name="acquireIncrement">5</property>
            <property name="initialPoolSize">10</property>
            <property name="minPoolSize">5</property>
            <property name="maxPoolSize">20</property>
        </named-config>
     
    </c3p0-config>

     

    还有更多可设置的参数,具体可查阅相关资料。

     

    步骤2:

    在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池

     

     

    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
     
    public class JdbcUtils_C3P0 {
       
        private static ComboPooledDataSource ds =null;
        //在静态代码块中创建数据库连接池
        static{
            try{
                //通过代码创建C3P0数据库连接池
                /*ds = new ComboPooledDataSource();
               ds.setDriverClass("com.mysql.jdbc.Driver");
               ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
                ds.setUser("root");
                ds.setPassword("123456");
                ds.setInitialPoolSize(10);
                ds.setMinPoolSize(5);
                ds.setMaxPoolSize(20);*/
               
                //通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下
                //ds = newComboPooledDataSource();//使用C3P0的默认配置来创建数据源
                ds = newComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源
               
            }catch (Exception e) {
                throw newExceptionInInitializerError(e);
            }
        }
       
       //从数据源中获取数据库连接
        public static Connection getConnection()throws SQLException{
            //从数据源中获取数据库连接
            return ds.getConnection();
        }
       
        //释放链接
        public static void release(Connection conn){
          
            if(conn!=null){
                try{
                    //将Connection连接对象还给数据库连接池
                    conn.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
     

     

    步骤3:

    在应用中获取连接

        

            Connection conn = null;
            PreparedStatement st = null;
            ResultSet rs = null;
            try{
                //获取数据库连接
                conn = JdbcUtils_C3P0.getConnection();
                ……
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                //释放资源
                JdbcUtils_C3P0release(conn);
            }
     

     

    其他连接池

    此外,还有其他的连接池可供选择,比如使用比较广泛的Proxool。Proxool是一种Java数据库连接池技术。是sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。

    proxool和 c3p0能够更好的支持高并发,但是在稳定性方面略逊于dpcp。

    可根据项目的实际需要来选择连接池。

    展开全文
  • 什么是连接池 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。 为什么要使用连接池  数据库连接是一种关键的有限的昂贵的资源,这一点在多...

    什么是连接池

    数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。

    为什么要使用连接池

     数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。  一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完都关闭连接,这样造成系统的 性能低下。 数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并讲这些连接组成一个连接池(简单说:在一个“池”里放了好多半成品的数据库联接对象),由应用程序动态地对池中的连接进行申请、使用和释放。对于多于连接池中连接数的并发请求,应该在请求队列中排队等待。并且应用程序可以根据池中连接的使用率,动态增加或减少池中的连接数。 连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器地服务效率,能够支持更多的客户服务。通过使用连接池,将大大提高程序运行效率,同时,我们可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。 

    传统的连接机制与数据库连接池的运行机制区别

    不使用连接池流程

    下面以访问MySQL为例,执行一个SQL命令,如果不使用连接池,需要经过哪些流程。

    不使用数据库连接池的步骤:

    1. TCP建立连接的三次握手
    2. MySQL认证的三次握手
    3. 真正的SQL执行
    4. MySQL的关闭
    5. TCP的四次握手关闭

    可以看到,为了执行一条SQL,却多了非常多我们不关心的网络交互。

    优点:

    1. 实现简单

    缺点:

    1. 网络IO较多
    2. 数据库的负载较高
    3. 响应时间较长及QPS较低
    4. 应用频繁的创建连接和关闭连接,导致临时对象较多,GC频繁
    5. 在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)

    使用连接池流程

    使用数据库连接池的步骤:

    第一次访问的时候,需要建立连接。 但是之后的访问,均会复用之前创建的连接,直接执行SQL语句。

    优点:

    1. 较少了网络开销
    2. 系统的性能会有一个实质的提升
    3. 没了麻烦的TIME_WAIT状态

    数据库连接池的工作原理

    连接池的工作原理主要由三部分组成,分别为

    1. 连接池的建立
    2. 连接池中连接的使用管理
    3. 连接池的关闭

            第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。

            第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是:

            当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。

            当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。

            该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。

            第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。

    连接池主要参数

    使用连接池时,要配置一下参数

    1. 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
    2. 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
    3. 最大空闲时间
    4. 获取连接超时时间
    5. 超时重试连接次数

    连接池需要注意的点

    1、并发问题

      为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为各个语言自身提供了对并发管理的支持像java,c#等等,使用synchronized(java)lock(C#)关键字即可确保线程是同步的。使用方法可以参考,相关文献。

    2、事务处理

      我们知道,事务具有原子性,此时要求对数据库的操作符合“ALL-OR-NOTHING”原则,即对于一组SQL语句要么全做,要么全不做。 
      我们知道当2个线程共用一个连接Connection对象,而且各自都有自己的事务要处理时候,对于连接池是一个很头疼的问题,因为即使Connection类提供了相应的事务支持,可是我们仍然不能确定那个数据库操作是对应那个事务的,这是由于我们有2个线程都在进行事务操作而引起的。为此我们可以使用每一个事务独占一个连接来实现,虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。 

    3、连接池的分配与释放

      连接池的分配与释放,对系统的性能有很大的影响。合理的分配与释放,可以提高连接的复用度,从而降低建立新连接的开销,同时还可以加快用户的访问速度。 
      对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他(如何能找到最合适的连接文章将在关键议题中指出);如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理捎后我会介绍这个线程的具体实现。

    4、连接池的配置与维护

      连接池中到底应该放置多少连接,才能使系统的性能最佳?系统可采取设置最小连接数(minConnection)和最大连接数(maxConnection)等参数来控制连接池中的连接。比方说,最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求上得到。 
      如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。

    数据库对比

    第一、二代连接池

    区分一个数据库连接池是属于第一代产品还是代二代产品有一个最重要的特征就是看它在架构和设计时采用的线程模型,因为这直接影响的是并发环境下存取数据库连接的性能。

    一般来讲采用单线程同步的架构设计都属于第一代连接池,二采用多线程异步架构的则属于第二代。比较有代表性的就是Apache Commons DBCP,在1.x版本中,一直延续着单线程设计模式,到2.x才采用多线程模型。

    用版本发布时间来辨别区分两代产品,则一个偷懒的好方法。以下是这些常见数据库连接池最新版本的发布时间:

    数据库连接池

    最新版本

    发布时间

    C3P0

    c3p0-0.9.5.2

    on 9 Dec 2015

    DBCP

    2.2.0

    27 December 2017

    Druid

    0.11.0

    Dec 4 2017

    HikariCP

    2.7.6

    2018-01-14

    从表中可以看出,C3P0已经很久没有更新了。DBCP更新速度很慢,基本处于不活跃状态,而Druid和HikariCP处于活跃状态的更新中,这就是我们说的二代产品了。

    二代产品对一代产品的超越是颠覆性的,除了一些“历史原因”,你很难再找到第二条理由说服自己不选择二代产品,但任何成功都不是偶然的,二代产品的成功很大程度上得益于前代产品们打下的基础,站在巨人的肩膀上,新一代的连接池的设计师们将这一项“工具化”的产品,推向了极致。其中,最具代表性的两款产品是:

    • HikariCP
    • Druid

    彻底死掉的C3P0

    C3P0是我使用的第一款数据库连接池,在很长一段时间内,它一直是Java领域内数据库连接池的代名词,当年盛极一时的Hibernate都将其作为内置的数据库连接池,可以业内对它的稳定性还是认可的。C3P0功能简单易用,稳定性好这是它的优点,但是性能上的缺点却让它彻底被打入冷宫。C3P0的性能很差,差到即便是同时代的产品相比它也是垫底的,更不用和Druid、HikariCP等相比了。正常来讲,有问题很正常,改就是了,但c3p0最致命的问题就是架构设计过于复杂,让重构变成了一项不可能完成的任务。随着国内互联网大潮的涌起,性能有硬伤的c3p0彻底的退出了历史舞台。

    咸鱼翻身的DBCP

    DBCP(DataBase Connection Pool)属于Apache顶级项目Commons中的核心子项目(最早在Jakarta Commons里就有),在Apache的生态圈中的影响里十分广泛,比如最为大家所熟知的Tomcat就在内部集成了DBCP,实现JPA规范的OpenJPA,也是默认集成DBCP的。但DBCP并不是独立实现连接池功能的,它内部依赖于Commons中的另一个子项目Pool,连接池最核心的“池”,就是由Pool组件提供的,因此,DBCP的性能实际上就是Pool的性能,DBCP和Pool的依赖关系如下表:

    Apache Commons DBCP

    Apache Commons Pool

    v1.2.2

    v1.3

    v1.3

    v1.5.4

    v1.4

    v1.5.4

    v2.0.x

    v2.2

    v2.1.x

    v2.4.2

    v2.2.x

    v2.5.0

    可以看到,因为核心功能依赖于Pool,所以DBCP本身只能做小版本的更新,真正大版本的更迭则完全依托于pool。有很长一段时间,pool都还是停留在1.x版本,这直接导致DBCP也更新乏力。很多依赖DBCP的应用在遇到性能瓶颈之后,别无选择,只能将其替换掉,DBCP忠实的拥趸tomcat就在其tomcat 7.0版本中,自己重新设计开发出了一套连接池(Tomcat JDBC Pool)。好在,在2013年事情终于迎来转机,13年9月Commons-Pool 2.0版本发布,14年2月份,DBCP也终于迎来了自己的2.0版本,基于新的线程模型全新设计的“池”让DBCP重焕青春,虽然和新一代的连接池相比仍有一定差距,但差距并不大,DBCP2.x版本已经稳稳达到了和新一代产品同级别的性能指标(见下图)。

    DBCP终于靠Pool咸鱼翻身,打了一个漂亮的翻身仗,但长时间的等待已经完全消磨了用户的耐心,与新一代的产品项目相比,DBCP没有任何优势,试问,谁会在有选择的前提下,去选择那个并不优秀的呢?也许,现在还选择DBCP2的唯一理由,就是情怀吧。

    性能无敌的HikariCP

    HikariCP号称“性能杀手”(It’s Faster),它的表现究竟如何呢,先来看下官网提供的数据:

    不光性能强劲,稳定性也不差:

    那它是怎么做到如此强劲的呢?官网给出的说明如下:

    • 字节码精简:优化代码,直到编译后的字节码最少,这样,CPU缓存可以加载更多的程序代码;
    • 优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码;
    • 自定义数组类型(FastStatementList)代替ArrayList:避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
    • 自定义集合类型(ConcurrentBag):提高并发读写的效率;
    • 其他缺陷的优化,比如对于耗时超过一个CPU时间片的方法调用的研究(但没说具体怎么优化)。

    可以看到,上述这几点优化,和现在能找到的资料来看,HakariCP在性能上的优势应该是得到共识的,再加上它自身小巧的身形,在当前的“云时代、微服务”的背景下,HakariCP一定会得到更多人的青睐。

    功能全面的Druid

    近几年,阿里在开源项目上动作频频,除了有像fastJson、dubbo这类项目,更有像AliSQL这类的大型软件,今天说的Druid,就是阿里众多优秀开源项目中的一个。它除了提供性能卓越的连接池功能外,还集成了SQL监控,黑名单拦截等功能,用它自己的话说,Druid是“为监控而生”。借助于阿里这个平台的号召力,产品一经发布就赢得了大批用户的拥趸,从用户使用的反馈来看,Druid也确实没让用户失望。

    相较于其他产品,Druid另一个比较大的优势,就是中文文档比较全面(毕竟是国人的项目么),在github的wiki页面,列举了日常使用中可能遇到的问题,对一个新用户来讲,上面提供的内容已经足够指导它完成产品的配置和使用了。

    下图为Druid自己提供的性能测试数据:

    现在项目开发中,我还是比较倾向于使用Durid,它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。

    Druid 相对于其他数据库连接池的优点

    1. 强大的监控特性,通过Druid提供的监控功能,可以清楚知道连接池和SQL的工作情况。

    a. 监控SQL的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈信息;

    b. SQL执行的耗时区间分布。什么是耗时区间分布呢?比如说,某个SQL执行了1000次,其中0~1毫秒区间50次,1~10毫秒800次,10~100毫秒100次,100~1000毫秒30次,1~10秒15次,10秒以上5次。通过耗时区间分布,能够非常清楚知道SQL的执行耗时情况;

    c. 监控连接池的物理连接创建和销毁次数、逻辑连接的申请和关闭次数、非空等待次数、PSCache命中率等。

    1. 方便扩展。Druid提供了Filter-Chain模式的扩展API,可以自己编写Filter拦截JDBC中的任何方法,可以在上面做任何事情,比如说性能监控、SQL审计、用户名密码加密、日志等等。
    2. Druid集合了开源和商业数据库连接池的优秀特性,并结合阿里巴巴大规模苛刻生产环境的使用经验进行优化。

    总结

    时至今日,虽然每个应用(需要RDBMS的)都离不开连接池,但在实际使用的时候,连接池已经可以做到“隐形”了。也就是说在通常情况下,连接池完成项目初始化配置之后,就再不需要再做任何改动了。不论你是选择Druid或是HikariCP,甚至是DBCP,它们都足够稳定且高效!之前讨论了很多关于连接池的性能的问题,但这些性能上的差异,是相较于其他连接池而言的,对整个系统应用来说,第二代连接池在使用过程中体会到的差别是微乎其微的,基本上不存在因为连接池的自身的配饰和使用导致系统性能下降的情况,除非是在单点应用的数据库负载足够高的时候(压力测试的时候),但即便是如此,通用的优化的方式也是单点改集群,而不是在单点的连接池上死扣。

     

    参考:

    http://rainbowhorse.site/2018/02/06/%E5%A4%A7%E8%AF%9D%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0/

    https://blog.csdn.net/frightingforambition/article/details/25464129

    https://juejin.im/entry/58fb03220ce4630061233c98

    展开全文
  • JDBC连接池原理及分析

    千次阅读 多人点赞 2018-09-11 13:45:07
    今天给大家分享一下,修真院官网Java任务1,深度思考中的知识点JDBC连接池原理 一、.背景介绍 什么是连接池 1)连接池,首先从字面意思理解,这是一个偏正短语,左偏右正,重点在池这个字上。 池(Pool)技术在一定...

    大家好,我是IT修真院西安分院第4期的JAVA学员,一枚正直纯洁善良的JAVA程序员。
    今天给大家分享一下,修真院官网Java任务1,深度思考中的知识点JDBC连接池原理
    一、.背景介绍
    什么是连接池
    1)连接池,首先从字面意思理解,这是一个偏正短语,左偏右正,重点在池这个字上。 池(Pool)技术在一定程度上可以明显优化服务器应用程序的性能,提高程序执行效率和降低系统资源开销。这里所说的池是一种广义上的池,比如数据库连接池、线程池、内存池、对象池等。其中,对象池可以看成保存对象的容器,在进程初始化时创建一定数量的对象。需要时直接从池中取出一个空闲对象,用完后并不直接释放掉对象,而是再放到对象池中以方便下一次对象请求可以直接复用。其他几种池的设计思想也是如此,池技术的优势是,可以消除对象创建所带来的延迟,从而提高系统的性能。
    2)数据库连接”是一种稀缺的资源,建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,不是关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。
    这里写图片描述
    这就好比是要从A城市去B城市,如果提前修了一条公路(类似我们这块连接池里的连接这个资源)我们要去就可以直接开车去了,若果没有公路,我们还得现修公路,这将非常耗时耗力。向下图中一样,我们连接数据库的时候先到连接池去找连接资源,如果有我们就直接使用,如果没有或者不够我们才创建一个连接。
    这里写图片描述
    二、知识剖析
    2.1连接池关键问题剖分析:
    1)并发问题
    为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。这个问题相对比较好解决,因为Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:
    public synchronized Connection getConnection()
    2)多数据库服务器和多用户
    对于大型的企业级应用,常常需要同时连接不同的数据库(如连接Oracle和Sybase)。如何连接不同的数据库呢?我们采用的策略是:设计一个符合单例模式的连接池管理类,在连接池管理类的唯一实例被创建时读取一个资源文件,其中资源文件中存放着多个数据库的url地址()?用户名()?密码()等信息。如tx.url=172.21.15.123:5000/tx_it,tx.user=yang,tx.password=yang321。根据资源文件提供的信息,创建多个连接池类的实例,每一个实例都是一个特定数据库的连接池。连接池管理类实例为每个连接池实例取一个名字,通过不同的名字来管理不同的连接池。
    对于同一个数据库有多个用户使用不同的名称和密码访问的情况,也可以通过资源文件处理,即在资源文件中设置多个具有相同url地址,但具有不同用户名和密码的数据库连接信息。
    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.jnshu.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.jnshu.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 连接池有几种?
    这个博客对几个常用的连接池的性能分析。https://www.cnblogs.com/linjian/p/4831088.html
    DBCP 、C3P0、BoneCP、Proxool、DDConnectionBroker、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。
    2 连接池有什么好处
    连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
    共享资源,连接池的使用解决了资源频繁分配、释放所造成的问题的。提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。
    3 如何选取连接池
    简单的说需要根据所要处理的业务量进行测试后选择合适的连接池,这牵扯到了技术选型。
    七、参考文献
    https://www.jianshu.com/p/beceba363798
    https://www.cnblogs.com/linjian/p/4831088.html
    https://www.zhihu.com/question/53589525/answer/275249556
    八、更多讨论
    1 、连接池最多存连接的个数如何设置
    2、使用连接池的优缺点
    3、哪种连接池更好用
    技能树.IT修真院“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
    这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导。快来与我一起学习吧~我的邀请码:28769611,或者你可以直接点击此链接:http://www.jnshu.com/login/1/28769611

    视频链接
    PP链接

    展开全文
  • 连接池

    2020-01-14 15:01:31
    1、连接池 问题:连接池是什么,有什么用? 连接池:就是创建一个容器,用于装入多个connection对象,在使用连接对象时,从容器中获取一个connection,使用完成后,在将这个connection重新装入到容器中。这个容器...
  • Java连接池详解

    万次阅读 2016-09-04 05:31:41
    对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的...数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量
  • 连接池究竟是什么

    千次阅读 2020-03-10 07:12:41
    通常如何通过连接访问下游? 工程架构中有很多访问下游的需求,下游包括但不限于服务/数据库/缓存,其通讯步骤是为: (1)与下游建立一个连接; (2)通过这个连接,收发请求; (3)交互结束,关闭连接,释放...
  • java中几个主流的数据库连接池

    万次阅读 多人点赞 2018-08-14 17:50:29
    这里所说的池是一种广义上的池,比如数据库连接池、线程池、内存池、对象池等。其中,对象池可以看成保存对象的容器,在进程初始化时创建一定数量的对象。需要时直接从池中取出一个空闲对象,用完后并不直接释放掉...
  • 连接池的作用及讲解

    千次阅读 2019-02-21 13:39:48
    连接池的作用就是为了提高性能。  连接池的作用:连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。...
  • 几种常用数据库连接池的使用

    千次阅读 2019-02-16 11:45:04
    一、应用程序直接获取数据库连接的缺点  用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要...二、使用数据库连接池优化程序性能 2.1、数据库连接池的基本概念  数据库连接是一种关键的有限的昂...
  • 前不久有俩个盆友和我探讨这些问题,我做了个简单的总结分享给打架,明天就是国庆了祝大家玩的开心,主要分享设计数据库连接池原理以及要处理关键点,本文只挑选某一种实现方式来简单阐述,暂不涉及事务相关。...
  • 数据库连接池原理详解与自定义连接池实现

    万次阅读 多人点赞 2017-05-17 18:20:19
    实现原理数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数制约。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的...
  • 数据库连接池的理解和使用

    万次阅读 多人点赞 2019-06-12 23:00:34
    一、什么是数据库连接池? 官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。 个人理解:创建数据库连接...
  • 数据库阿里连接池 druid配置详解

    万次阅读 多人点赞 2016-12-19 09:55:25
    java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,有不得不使用数据库连接池。数据库连接池有很多选择,c3p、dhcp、proxool等,druid作为一名后起之秀,凭借其出色的性能,也逐渐印入了大家的眼帘。...
  • 数据库连接池到底应该设置多大?

    万次阅读 多人点赞 2017-12-13 21:57:05
    我在研究HikariCP(一个数据库连接池)时无意间在HikariCP的Github wiki上看到了一篇文章(即前面给出的链接),这篇文章有力地消除了我一直以来的疑虑,看完之后感觉神清气爽。故在此做译文分享。  接下来...
  • MySql数据库连接池

    万次阅读 2018-07-24 21:40:17
    官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对连接池中的连接进行申请,使用,释放。 理解:创建数据库连接池是一个很耗时的操作,也...
  • DRUID连接池的实用 配置详解

    万次阅读 2019-06-19 13:00:19
    DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池(据说是目前最好的连接池...
  • c3p0,dbcp与druid 三大连接池的区别

    万次阅读 多人点赞 2017-05-26 09:41:19
     说到druid,这个是在开源中国开源项目中看到的,说是比较好的数据连接池。于是乎就看看。扯淡就到这。  下面就讲讲用的比较多的数据库连接池。(其实我最先接触的是dbcp这个)  1)DBCP  DBCP是一个依赖...
  • 《深入理解mybatis原理》 Mybatis数据源与连接池

    万次阅读 多人点赞 2014-07-10 23:33:10
    本文将通过对MyBatis框架的数据源结构进行详尽的分析,并且深入解析MyBatis的连接池。  本文首先会讲述MyBatis的数据源的分类,然后会介绍数据源是如何加载和使用的。紧接着将分类介绍UNPOOLED、POOLED和JNDI类型...
  • jdbc连接池实现

    千次阅读 2018-08-13 22:25:32
    连接池我们一直再用,比如druid、c3p0、tomcat的连接池等等,包括数据库本身也会有连接池,今天突然想研究一下数据库连接池是怎么实现的。现总结一下: 数据库连接池的目的: 减少频繁的创建/销毁连接,因为一次...
1 2 3 4 5 ... 20
收藏数 415,823
精华内容 166,329
关键字:

连接池