03:Java数据库连接池:Druid 连接池使用详解

阿里巴巴,数据库连接池,Druid,连接池界的小龙女

Druid的简介

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,

包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

同时Druid不仅仅是一个数据库连接池,它包括四个部分:

    Druid是一个JDBC组件,它包括三个部分:

    基于Filter-Chain模式的插件体系。

    DruidDataSource 高效可管理的数据库连接池。

    SQLParser

Druid的功能

1、替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。

2、可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。

3、数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。

4、SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。

5、扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。


   阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。

Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。

Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。

简单SQL语句用时10微秒以内,复杂SQL用时30微秒。

通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。


druid-1.0.31-javadoc.jar

druid-1.0.31-sources.jar

druid-1.0.31.jar


druid-1.1.9-javadoc.jar

druid-1.1.9-sources.jar

druid-1.1.9.jar 


Druid属性表:

属性(Parameter)默认值(Default)描述(Description)
username
连接数据库的用户名
password  
连接数据库的密码
jdbcUrl
同DBCP中的jdbcUrl属性
driverClassName根据url自动识别这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName
initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时                     *参见DBCP中的initialSize属性
maxActive8最大连接池数量(Maximum   number of Connections a pool will maintain at any given   time.)                        *参见DBCP中的maxTotal属性
maxIdle8已经不再使用,配置了也没效果                          *参见DBCP中的maxIdle属性
minIdle
最小连接池数量
maxWait
获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
poolPreparedState- mentsFALSE是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。
maxOpenPrepared- Statements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。        在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
testOnBorrowTRUE申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturnFALSE归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdleFALSE建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
validationQuery
用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。在mysql中通常为select   'x',在oracle中通常为select 1 from dual
timeBetweenEviction-RunsMillis
1)   Destroy线程会检测连接的间隔时间        2)   testWhileIdle的判断依据
minEvictableIdle- TimeMillis
Destory线程中如果检测到当前连接的最后活跃时间和当前时间的差值大于minEvictableIdleTimeMillis,则关闭当前连接。
removeAbandoned
对于建立时间超过removeAbandonedTimeout的连接强制关闭
removeAbandoned-Timeout
指定连接建立多长时间就需要被强制关闭
logAbandonedFALSE指定发生removeabandoned的时候,是否记录当前线程的堆栈信息到日志中
filters
属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
    1)监控统计用的filter:stat              
    2)日志用的filter:log4j   
    3)防御sql注入的filter:wall


一、Spring Druid 数据源配置:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

   <property name="driverClassName" value="${jdbc.mysql.driverClassName}"></property>

   <property name="url" value="${jdbc.mysql.url}" />

   <property name="username" value="${jdbc.mysql.username}" />

   <property name="password" value="${jdbc.mysql.password}" />

   <property name="initialSize" value="1" /><!-- 配置初始化大小、最小、最大 -->

   <property name="minIdle" value="1" /><!-- 最小连接池数量 -->

   <property name="maxActive" value="5" /><!-- 最大连接池数量 -->

   <property name="maxWait" value="60000" /><!-- 配置获取连接等待超时的时间 -->

   <property name="timeBetweenEvictionRunsMillis" value="60000" /><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->

   <property name="minEvictableIdleTimeMillis" value="300000" /><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->

   <property name="poolPreparedStatements" value="true" /><!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->

   <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />

   <property name="filters" value="stat" /><!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->

</bean>


二、Tomcat 8.0 中JNDI配置方式(有几种配置方式):

com.alibaba.druid.pool.DruidDataSourceFactory实现了javax.naming.spi.ObjectFactory,可以作为JNDI数据源来配置

 1、全局配置方式:

   a、在 server.xml 文件的 <GlobalNamingResources> 节点中,增加如下配置信息:   

    <Resource 

       name="jdbc/MySQLDataSource" 

       factory="com.alibaba.druid.pool.DruidDataSourceFactory" 

       auth="Container" type="javax.sql.DataSource" 

       driverClassName="com.mysql.jdbc.Driver" 

       url="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF-8" 

       username="root" password="" 

       maxActive="50" maxWait="10000" 

       removeabandoned="true" removeabandonedtimeout="60" 

       logabandoned="false" filters="stat"/>

   如图:

   211497979288325606.png

  b、在 context.xml 文件中增加如下配置信息:

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

   如图:

   211497979433296761.png

  c、注意,需要将 druid-1.0.31.jar 包放到 apache-tomcat-8.0\lib\ 目录下;

  d、MySQL驱动 mysql-connector-java-5.1.41-bin.jar ,可以放在项目的 WEB-INF\lib 目录下;
  e、Java代码调用方法:

   try {

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

      Context ctx = new InitialContext();

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

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

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

      Connection conn = ds.getConnection();

       System.out.println(conn.getMetaData().getUserName());

    } catch (NamingException | SQLException e) {

      e.printStackTrace();

    }

2、局部配置方式:

   a、在项目的 META-INF 文件夹下新建一个 context.xml 文件;

   b、context.xml 文件内容如下:(其实就是将全局配置中的内容放入其中)

   <?xml version="1.0" encoding="UTF-8"?>

    <Context>

      <Resource name="jdbc/MySQLDataSource2" factory="com.alibaba.druid.pool.DruidDataSourceFactory" auth="Container"

        type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" 

         url="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF-8"

        username="root" password="" maxActive="50" maxWait="10000" removeabandoned="true" removeabandonedtimeout="60" logabandoned="false"

        filters="stat" />

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

    </Context>

    c、Java代码调用同上:

      try {

         Context ctx = new InitialContext();// 1、初始化名称查找上下文

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

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

         Connection conn = ds.getConnection();// 3、通过ds获取数据库连接对象

         System.out.println(conn.getMetaData().getUserName());

       } catch (NamingException | SQLException e) {

         e.printStackTrace();

       }

 



Java代码中获取JNDI数据源: