文档章节

主流Java数据库连接池比较与开发配置实战

fysuccess
 fysuccess
发布于 2017/03/27 16:29
字数 3411
阅读 138
收藏 0

1.数据库连接池概述

数据库连接的建立是一种耗时、性能低、代价高的操作,频繁的数据库连接的建立和关闭极大的影响了系统的性能。数据库连接池是系统初始化过程中创建一定数量的数据库连接放于连接池中,当程序需要访问数据库时,不再建立一个新的连接,而是从连接池中取出一个已建立的空闲连接,使用完毕后,程序将连接归还到连接池中,供其他请求使用,从而实现的资源的共享,连接的建立、断开都由连接池自身来管理。

数据库连接池为系统的运行带来了以下优势:昂贵的数据库连接资源得到重用;减少了数据库连接建立和释放的时间开销,提高了系统响应速度;统一的数据库连接管理,避免了连接资源的泄露。

数据库连接池运行机制:

系统初始化时创建连接池,程序操作数据库时从连接池中获取空闲连接,程序使用完毕将连接归还到连接池中,系统退出时,断开所有数据库连接并释放内存资源。

2.主流数据库连接池比较

常用的主流开源数据库连接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等

C3p0: 开源的JDBC连接池,实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有hibernate、spring等。单线程,性能较差,适用于小型系统,代码600KB左右。

DBCP (Database Connection Pool):由Apache开发的一个Java数据库连接池项目, Jakarta commons-pool对象池机制,Tomcat使用的连接池组件就是DBCP。单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar,预先将数据库连接放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完再放回。单线程,并发量低,性能不好,适用于小型系统。

Tomcat Jdbc Pool:Tomcat在7.0以前都是使用common-dbcp做为连接池组件,但是dbcp是单线程,为保证线程安全会锁整个连接池,性能较差,dbcp有超过60个类,也相对复杂。Tomcat从7.0开始引入了新增连接池模块叫做Tomcat jdbc pool,基于Tomcat JULI,使用Tomcat日志框架,完全兼容dbcp,通过异步方式获取连接,支持高并发应用环境,超级简单核心文件只有8个,支持JMX,支持XA Connection。

BoneCP:官方说法BoneCP是一个高效、免费、开源的Java数据库连接池实现库。设计初衷就是为了提高数据库连接池性能,根据某些测试数据显示,BoneCP的速度是最快的,要比当时第二快速的连接池快25倍左右,完美集成到一些持久化产品如Hibernate和DataNucleus中。BoneCP特色:高度可扩展,快速;连接状态切换的回调机制;允许直接访问连接;自动化重置能力;JMX支持;懒加载能力;支持XML和属性文件配置方式;较好的Java代码组织,100%单元测试分支代码覆盖率;代码40KB左右。

Druid:Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能,是一个可用于大数据实时查询和分析的高容错、高性能的开源分布式系统,尤其是当发生代码部署、机器故障以及其他产品系统遇到宕机等情况时,Druid仍能够保持100%正常运行。主要特色:为分析监控设计;快速的交互式查询;高可用;可扩展;Druid是一个开源项目,源码托管在github上。

主流连接池各项功能对比如下:

3.数据库连接池Spring集成配置与JNDI配置

下面针对每一种连接池的使用方法,在开发中如何配置给出spring集成配置和在tomcat的conf/context.xml文件中配置2种方式,限于篇幅只给出基本参数,详细参数可自行研究。

3.1 阿里Druid连接池

Maven依赖

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.0.28</version>
</dependency>

Spring集成配置方式

<!--Spring Druid 数据源配置-->  
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">  
        <!-- 基本属性 url、user、password -->  
        <property name="url" value="${jdbc.url}" />  
        <property name="username" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <!-- 配置初始化大小、最小、最大 -->  
        <property name="initialSize" value="1" />  
        <property name="minIdle" value="1" />  
        <property name="maxActive" value="20" />  
        <!-- 配置获取连接等待超时的时间 -->  
        <property name="maxWait" value="60000" />  
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->  
        <property name="timeBetweenEvictionRunsMillis" value="60000" />  
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->  
        <property name="minEvictableIdleTimeMillis" value="300000" />  
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->  
        <property name="poolPreparedStatements" value="true" />  
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />  
        <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->  
        <property name="filters" value="stat" />  
    </bean>  
    Web.xml配置  
     <!--druid WebStatFilter用于采集web-jdbc关联监控的数据-->  
      <filter>  
        <filter-name>DruidWebStatFilter</filter-name>  
        <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>  
        <init-param>  
          <param-name>exclusions</param-name>  
          <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>  
        </init-param>  
      </filter>  
      <filter-mapping>  
        <filter-name>DruidWebStatFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
      </filter-mapping>  
      <!--druid访问监控界面 /druid/index.html-->  
      <servlet>  
        <servlet-name>DruidStatView</servlet-name>  
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>  
      </servlet>  
      <servlet-mapping>  
        <servlet-name>DruidStatView</servlet-name>  
        <url-pattern>/druid/*</url-pattern>  
      </servlet-mapping>  

Tomcat中context.xml文件JNDI配置方式

com.alibaba.druid.pool.DruidDataSourceFactory实现了javax.naming.spi.ObjectFactory,可以作为JNDI数据源来配置
<TOMCAT_HOME>/conf/context.xml配置JNDI方式

<Resource  
        name="jdbc/MysqlDataSource"  
        factory="com.alibaba.druid.pool.DruidDataSourceFactory"  
        auth="Container"  
        type="javax.sql.DataSource"  
        driverClassName="com.mysql.jdbc.Driver"  
        url="jdbc:mysql://192.168.1.233:3306/lead_oams?useUnicode=true&characterEncoding=utf-8"  
        username="lead_system"  
        password="password"  
        maxActive="50"  
        maxWait="10000"  
        removeabandoned="true"  
        removeabandonedtimeout="60"  
        logabandoned="false"  
        filters="stat"/>  

 web.xml配置

<!--MySQL数据库JNDI数据 -->  
  <resource-ref>  
      <description>MySQL DB Connection</description>  
      <res-ref-name>jdbc/MysqlDataSource</res-ref-name>  
      <res-type>javax.sql.DataSource</res-type>  
      <res-auth>Container</res-auth>  
  </resource-ref>  

Java代码中获取JNDI数据源

  //1、初始化名称查找上下文

  Context ctx =new InitialContext();

  //2、通过JNDI名称找到DataSource

 DruidDataSource ds = (DruidDataSource)ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通过ds获取数据库连接对象

  Connectionconn = ds.getConnection();

3.2 BoneCP连接池

Maven依赖

<dependency>
  <groupId>com.jolbox</groupId>
  <artifactId>bonecp-spring</artifactId>
  <version>0.8.0.RELEASE</version>
</dependency>

Spring集成BoneCP配置方式

<!-- Spring BoneCP 数据源配置-->  
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">  
        <!-- 数据库驱动 -->  
        <property name="driverClass" value="${jdbc.driver}" />  
        <!-- 相应驱动的jdbcUrl -->  
        <property name="jdbcUrl" value="${jdbc.url}" />  
        <!-- 数据库的用户名 -->  
        <property name="username" value="${jdbc.username}" />  
        <!-- 数据库的密码 -->  
        <property name="password" value="${jdbc.password}" />  
        <!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 -->  
        <property name="idleConnectionTestPeriod" value="60" />  
        <!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 -->  
        <property name="idleMaxAge" value="30" />  
        <!-- 每个分区最大的连接数 -->  
        <property name="maxConnectionsPerPartition" value="150" />  
        <!-- 每个分区最小的连接数 -->  
        <property name="minConnectionsPerPartition" value="5" />  
    </bean>  

Tomcat中BoneCP使用JNDI配置方式

<Resource  
  name="JNDIName"  
  auth="Container"  
  type="com.jolbox.bonecp.BoneCPDataSource"  
  factory="org.apache.naming.factory.BeanFactory"  
  driverClass="oracle.jdbc.driver.OracleDriver"  
  username="root"   
    password="root"   
  jdbcUrl="jdbc:mysql://localhost:3306/test"  
  idleConnectionTestPeriod="0"  
  idleMaxAge="10"  
  partitionCount="1"  
  maxConnectionsPerPartition="5"  
  minConnectionsPerPartition="1"  
  connectionTestStatement=""  
  initSQL="select 1 from dual"/>  

Java代码中获取JNDI数据源

  //1、初始化名称查找上下文

  Context ctx =new InitialContext();

  //2、通过JNDI名称找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通过ds获取数据库连接对象

  Connectionconn = ds.getConnection();

3.3 Tomcat Jdbc Pool连接池

Maven依赖

<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-jdbc</artifactId>
  <version>7.0.75</version>
</dependency>
<dependency>
  <groupId>org.apache.tomcat</groupId>
  <artifactId>tomcat-juli</artifactId>
  <version>7.0.75</version>
</dependency>

Spring集成Tomcat Jbdc Pool配置方式

<!--tomcat jdbc pool数据源配置-->   
    <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">  
        <property name="poolProperties">  
        <bean class="org.apache.tomcat.jdbc.pool.PoolProperties">  
        <!--driverClassName url username password-->  
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
        <property name="url" value="jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"/>  
        <property name="username" value="root"/>  
        <property name="password" value="root"/>  
        <!--jmx support-->  
        <property name="jmxEnabled" value="true"/>  
        <property name="testWhileIdle" value="true"/>  
        <property name="testOnBorrow" value="true"/>  
        <property name="testOnReturn" value="false"/>  
        <property name="validationInterval" value="30000"/>  
        <property name="validationQuery" value="SELECT 1"/>  
        <property name="timeBetweenEvictionRunsMillis" value="30000"/>  
        <!--最大连接-->  
        <property name="maxActive" value="50"/>  
        <!--初始化连接-->  
        <property name="initialSize" value="5"/>  
        <!--最长等待时间ms-->  
        <property name="maxWait" value="10000"/>  
        <property name="minEvictableIdleTimeMillis" value="30000"/>  
        <property name="minIdle" value="10"/>  
        <!--是否允许日志-->  
        <property name="logAbandoned" value="false"/>  
        <property name="removeAbandoned" value="true"/>  
        <property name="removeAbandonedTimeout" value="60"/>  
        <property name="jdbcInterceptors" value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"/>  
    </bean>  

Tomcat中context.xml文件JNDI配置方式

<Resource     
    name="jdbc/test"    
    auth="Container"    
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"    
    testWhileIdle="true"    
    testOnBorrow="true"    
    testOnReturn="false"    
    validationQuery="SELECT 1"    
    validationInterval="30000"    
    timeBetweenEvictionRunsMillis="30000"    
    driverClassName="com.mysql.jdbc.Driver"    
    maxActive="100"    
    maxIdle="40"  
    maxWait="12000"    
    initialSize="10"    
    removeAbandonedTimeout="60"    
    removeAbandoned="true"    
    logAbandoned="true"    
    minEvictableIdleTimeMillis="30000"    
    jmxEnabled="true"    
    jdbcInterceptors=    
     "org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"    
    username="root"   
    password="root"   
    type="javax.sql.DataSource"     
    url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>   

Java代码中获取JNDI数据源

//1、初始化名称查找上下文

  Context ctx =new InitialContext();

  //2、通过JNDI名称找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/test");

  //3、通过ds获取数据库连接对象

  Connectionconn = ds.getConnection();

3.4 Apache DBCP连接池

Maven依赖

<dependency>
  <groupId>commons-dbcp</groupId>
  <artifactId>commons-dbcp</artifactId>
  <version>1.4</version>
</dependency>
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.2.2</version>
</dependency>
<dependency>
  <groupId>commons-pool</groupId>
  <artifactId>commons-pool</artifactId>
  <version>1.6</version>
</dependency>

Spring集成DBCP配置方式

<!-- 配置dbcp数据源 -->  
     <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">  
       <property name="driverClassName" value="${jdbc.driverClassName}"/>  
       <property name="url" value="${jdbc.url}"/>  
       <property name="username" value="${jdbc.username}"/>  
       <property name="password" value="${jdbc.password}"/>  
       <!-- 池启动时创建的连接数量 -->  
       <property name="initialSize" value="5"/>  
       <!-- 同一时间可以从池分配的最多连接数量。设置为0时表示无限制。 -->  
       <property name="maxActive" value="50"/>  
       <!-- 池里不会被释放的最多空闲连接数量。设置为0时表示无限制。 -->  
       <property name="maxIdle" value="10"/>  
       <!-- 在不新建连接的条件下,池中保持空闲的最少连接数。 -->  
       <property name="minIdle" value="3"/>  
       <!-- 设置自动回收超时连接 -->    
       <property name="removeAbandoned" value="true" />  
       <!-- 自动回收超时时间(以秒数为单位) -->    
       <property name="removeAbandonedTimeout" value="200"/>  
       <!-- 设置在自动回收超时连接的时候打印连接的超时错误  -->   
       <property name="logAbandoned" value="true"/>  
       <!-- 等待超时以毫秒为单位,在抛出异常之前,池等待连接被回收的最长时间(当没有可用连接时)。设置为-1表示无限等待。-->    
       <property name="maxWait" value="100"/>    
     </bean>  

Tomcat中context.xml文件JNDI配置方式

<Resource name="/jdbc/test"   
        type="javax.sql.DataSource"   
        driverClassName="com.sybase.jdbc3.jdbc.SybDataSource"   
        url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"   
        username="root"   
        password="root"   
        initialSize="5"  
        maxActive="50"   
        maxIdle="10"   
        minIdle="3"  
        maxWait="50000" />  

Java代码中获取JNDI数据源

//1、初始化名称查找上下文

  Context ctx =new InitialContext();

  //2、通过JNDI名称找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/test");

  //3、通过ds获取数据库连接对象

  Connectionconn = ds.getConnection();

3.5 C3p0连接池

Maven依赖

<dependency>
  <groupId>c3p0</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.1.2</version>
</dependency>

Spring集成配置方式

<!-- Spring配置c3p0数据源 -->  
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
        <property name="jdbcUrl" value="${jdbc.url}" />  
        <property name="driverClass" value="${jdbc.driverClassName}" />  
        <property name="user" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <!--连接池中保留的最大连接数。Default: 15 -->  
        <property name="maxPoolSize" value="100" />  
        <!--连接池中保留的最小连接数。-->  
        <property name="minPoolSize" value="1" />  
        <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->  
        <property name="initialPoolSize" value="10" />  
        <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->  
        <property name="maxIdleTime" value="30" />  
        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->  
        <property name="acquireIncrement" value="5" />  
        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。Default: 0-->  
        <property name="maxStatements" value="0" />  
        <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->  
        <property name="idleConnectionTestPeriod" value="60" />  
        <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->  
        <property name="acquireRetryAttempts" value="30" />  
        <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。Default: false-->  
        <property name="breakAfterAcquireFailure" value="true" />  
        <!--因性能消耗大请只在需要的时候使用它。Default: false -->  
        <property name="testConnectionOnCheckout"  value="false" />          
    </bean>  

Tomcat中context.xml文件JNDI配置方式

<Resource   
         name="jdbc/MysqlDataSource"   
         auth="Container"  
         factory="org.apache.naming.factory.BeanFactory"   
         type="com.mchange.v2.c3p0.ComboPooledDataSource"  
         driverClass="com.mysql.jdbc.Driver"  
         idleConnectionTestPeriod="60"  
        maxPoolSize="50"   
        minPoolSize="2"  
        acquireIncrement="2"   
        user="root"   
        password="root"  
        jdbcUrl="jdbc:mysql://localhost:3306/test"/>

Java代码中获取JNDI数据源

  //1、初始化名称查找上下文

  Context ctx =new InitialContext();

  //2、通过JNDI名称找到DataSource

  DataSource ds= (DataSource) ctx.lookup("java:comp/env/jdbc/MysqlDataSource");

  //3、通过ds获取数据库连接对象

  Connectionconn = ds.getConnection();

4.总结

     本文所比较的5种数据库连接池在性能方面,根据个人测试结果和参考网上资料Druid > TomcatJDBC > DBCP > C3P0,BoneCP的性能方面没有深入比较,应该和Tomcat Jdbc差不多。对于小型的系统,并发压力不大时,选择哪一种数据库连接池差别不会很大,主要考虑的应该是连接池的稳定性。当并发量较高时,一般不会选择使用DBCP和C3P0,选择Druid是较好的。本文给出了5种数据库连接池通过Spring配置和Tomcat JNDI方式配置两种方式,Spring配置一般使用单独的属性文件,每一个连接池都提供了使用代码创建的方式,使用方式也比较类似,感兴趣可以自行研究。另外连接不同的数据库时,在配置方面的差异主要在driverClass和jdbcUrl两项,优化配置项可以另行考虑。

欢迎大家关注博主订阅号“Java技术日志”,提供Java相关技术分享,从Java编程基础到Java高级技术,从JavaWeb技术基础Jsp、Servlet、JDBC到SSH、SSM开发框架,从REST风格接口设计到分布式项目实战。剖析主流开源技术框架,用亲身实践来谱写深度Java技术日志。

© 著作权归作者所有

fysuccess
粉丝 2
博文 8
码字总数 13803
作品 0
架构师
私信 提问
【Java学习路线】新手该如何一步步的学习 Java

新手该如何一步步的学习 Java? 如果真的想学Java,最好要循序渐进,有章有法的学习它! 今天小慕就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容。 首先,给大家分享一张以 企业...

Eddie_yang
2018/11/15
2.4K
0
主流Java数据库连接池比较及前瞻

本文转载自微信公众号「工匠小猪猪的技术世界」 主流数据库连接池 常用的主流开源数据库连接池有C3P0、DBCP、Tomcat Jdbc Pool、BoneCP、Druid等 C3p0: 开源的JDBC连接池,实现了数据源和JND...

渣渣(Charles)
2018/04/30
0
0
Hinernate中获得数据库连接池的方式及应用

Hibernate可以与任何一种java应用的运行环境集成。Java应用的运行环境可分为两种。 (1)受管理环境(Managed environment):由容器负责管理各种共享资源(如线程池和数据库连接池),以及管理...

_守望者_
2014/04/22
289
0
数据库连接池clearpool(java实现)详解

clearpool的maven项目托管在https://github.com/xionghuiCoder/clearpool,同时也可以在http://www.oschina.net/p/clearpool上了解它的简单介绍。 首先大家可能会问,现在开源社区已经有了很...

xionghuiCoder
2014/08/20
5.4K
16
Spring Boot 配置数据库连接池,但日志却每次都新建连接的解决办法

Spring Boot 配置数据库连接池,但日志却每次都新建连接的解决办法 一号门-程序员的工作,程序员的生活(java,python,delphi实战)2018-07-202732 阅读 Java...

一号门-程序员的工作,程序员的生活(java,python,delphi实战)
2018/07/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

ERC-777以太坊新代币标准解读

ERC777是一个新的高级代币标准,可以视为ERC20的升级版本,因此它解决了ERC20以及ERC223存在的一些问题,开发者可以根据自己的具体需求进行选型。 1、使用ERC820进行合约注册 有别于ERC20的自...

汇智网教程
37分钟前
3
0
代理模式之JDK动态代理 — “JDK Dynamic Proxy“

动态代理的原理是什么? 所谓的动态代理,他是一个代理机制,代理机制可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成,通过代理可以有效的让调...

code-ortaerc
今天
5
0
学习记录(day05-标签操作、属性绑定、语句控制、数据绑定、事件绑定、案例用户登录)

[TOC] 1.1.1标签操作v-text&v-html v-text:会把data中绑定的数据值原样输出。 v-html:会把data中值输出,且会自动解析html代码 <!--可以将指定的内容显示到标签体中--><标签 v-text=""></......

庭前云落
今天
8
0
VMware vSphere的两种RDM磁盘

在VMware vSphere vCenter中创建虚拟机时,可以添加一种叫RDM的磁盘。 RDM - Raw Device Mapping,原始设备映射,那么,RDM磁盘是不是就可以称作为“原始设备映射磁盘”呢?这也是一种可以热...

大别阿郎
今天
12
0
【AngularJS学习笔记】02 小杂烩及学习总结

本文转载于:专业的前端网站☞【AngularJS学习笔记】02 小杂烩及学习总结 表格示例 <div ng-app="myApp" ng-controller="customersCtrl"> <table> <tr ng-repeat="x in names | orderBy ......

前端老手
昨天
16
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部