Druid数据库连接池

Druid简介:

常用的数据库连接池:C3P0、DBCP、proxool、Druid

Druid的特点:

  • 高性能。测试数据表明,Druid比DBCP、C3P0、BoneCP的性能都好很多
  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助
  • 可扩展性,提供基于Filter-Chain模式的扩展机制,Druid提供了一些内置的扩展机制,包括StatLogTrace、HA等扩展。
  • 替换DBCP,配置和DBCP兼容,可以方便替换DBCP。
  • 适合大规模应用。结合Alibaba使用数据库连接池的经验,避免一些已知问题,例如数据库不可用恢复之后产生的连接风暴问题等。

 

Druid提供一个手工编写的高性能的方便扩展的SQL Parser。将会支持MySQL、Oracle等流行关系数据库的SQL Parser。

Parser组件包括如下几个部分:

  • Lexer 词法解析
  • Parser,Parser包括ExprParser,各种StatementParser。
  • AST, Abstract Syntax Tree。ParserParse出来的结果就是AST。
  • Visitor。对AST做各种处理,比如FormatOutput,遍历等等。

 

监控:

  • Druid的统计信息定义代码实现在com/alibaba/druid/stat下。所有的Stat都全局静态变量的方式保存,这样做使得外部获取监控信息更容易。
  • 获取Druid监控信息的入口是com.alibaba.druid.stat.JdbcStatManager
  • Druid的监控统计信息都是通过StatFilter来实现的,如果你需要数据源进行监控,那你需要启用StatFilter

 

Subversion

http://code.alibabatech.com/svn/druid/trunk/

Download

Binary: http://code.alibabatech.com/mvn/releases/com/alibaba/druid/0.1.2/druid-0.1.2.jar
Source: http://code.alibabatech.com/mvn/releases/com/alibaba/druid/0.1.2/druid-0.1.2-sources.jar

 

Maven

Alibaba Open Source Repository

<repositories>
	<repository>
		<id>alibaba-opensource</id>
		<name>alibaba-opensource</name>
		<url>http://code.alibabatech.com/mvn/releases/</url>
		<layout>default</layout>
	</repository>
	<repository>
		<id>alibaba-opensource-snapshot</id>
		<name>alibaba-opensource-snapshot</name>
		<url>http://code.alibabatech.com/mvn/snapshots/</url>
		<layout>default</layout>
	</repository>
</repositories>

依赖配置

<dependencies>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>druid</artifactId>
		<version>0.1.2</version>
	</dependency>
</dependencies>

 

Druid应用:

druid的常用配置项如下:

配置

缺省值

说明

name

 

配置这个属性的意义在于,如果存在多个数据源,监控的时候
可以通过名字来区分开来。如果没有配置,将会生成一个名字,
格式是:"DataSource-" + System.identityHashCode(this)

jdbcUrl

 

连接数据库的url,不同数据库不一样。例如:
mysql : jdbc:mysql://127.0.0.1:3306/druid2 
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto

username

 

连接数据库的用户名

password

 

连接数据库的密码。如果你不希望密码直接写在配置文件中,
可以使用ConfigFilter。详细看这里:
https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter

driverClassName

根据url自动识别

这一项可配可不配,如果不配置druid会根据url自动识别dbType
然后选择相应的driverClassName

initialSize

0

初始化时建立物理连接的个数。初始化发生在显示调用init方法,
或者第一次getConnection

maxActive

8

最大连接池数量

maxIdle

8

已经不再使用,配置了也没效果

minIdle

 

最小连接池数量

maxWait

 

获取连接时最大等待时间,单位毫秒。配置了maxWait之后,
缺省启用公平锁,并发效率会有所下降,
如果需要可以通过配置useUnfairLock属性为true使用非公平锁。

poolPreparedStatements

false

是否缓存preparedStatement,也就是PSCache
PSCache对支持游标的数据库性能提升巨大,比如说oracle
mysql5.5以下的版本中没有PSCache功能,建议关闭掉。
5.5及以上版本有PSCache,建议开启。

maxOpenPreparedStatements

-1

要启用PSCache,必须配置大于0,当大于0时,
poolPreparedStatements自动触发修改为true
Druid中,不会存在OraclePSCache占用内存过多的问题,
可以把这个数值配置大一些,比如说100

validationQuery

 

用来检测连接是否有效的sql,要求是一个查询语句。
如果validationQuerynulltestOnBorrowtestOnReturn
testWhileIdle都不会其作用。在mysql中通常为select 'x',在oracle中通常为
select 1 from dual

testOnBorrow

true

申请连接时执行validationQuery检测连接是否有效,
做了这个配置会降低性能。

testOnReturn

false

归还连接时执行validationQuery检测连接是否有效,
做了这个配置会降低性能

testWhileIdle

false

建议配置为true,不影响性能,并且保证安全性。
申请连接的时候检测,如果空闲时间大于
timeBetweenEvictionRunsMillis
执行validationQuery检测连接是否有效。

timeBetweenEvictionRunsMillis

 

有两个含义:
1) Destroy线程会检测连接的间隔时间
 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明

numTestsPerEvictionRun

 

不再使用,一个DruidDataSource只支持一个EvictionRun

minEvictableIdleTimeMillis

 

Destory线程中如果检测到当前连接的最后活跃时间和当前时间的差值大于
minEvictableIdleTimeMillis,则关闭当前连接。

connectionInitSqls

 

物理连接初始化的时候执行的sql

exceptionSorter

根据dbType自动识别

当数据库抛出一些不可恢复的异常时,抛弃连接

filters

 

属性类型是字符串,通过别名的方式配置扩展插件,
常用的插件有:
监控统计用的filter:stat 
日志用的filter:log4j
 防御sql注入的filter:wall

proxyFilters

 

类型是List<com.alibaba.druid.filter.Filter>
如果同时配置了filtersproxyFilters
是组合关系,并非替换关系

removeAbandoned

 

对于建立时间超过removeAbandonedTimeout的连接强制关闭

removeAbandonedTimeout

 

指定连接建立多长时间就需要被强制关闭

logAbandoned

 

指定发生removeabandoned的时候,是否记录当前线程的堆栈信息到日志中

 

结合Spring配置数据库连接池:

url:jdbc:mysql://localhost:3306/dragoon_v25_masterdb  
driverClassName:com.mysql.jdbc.Driver  
username:root  
password:aaaaaaaa  
       
filters:stat  
   
maxActive:20  
initialSize:1  
maxWait:60000  
minIdle:10  
#maxIdle:15  
   
timeBetweenEvictionRunsMillis:60000  
minEvictableIdleTimeMillis:300000  
   
validationQuery:SELECT 'x'  
testWhileIdle:true  
testOnBorrow:false  
testOnReturn:false  
#poolPreparedStatements:true  
maxOpenPreparedStatements:20  
  
#禁用对于长时间不使用的连接强制关闭的功能  
removeAbandoned:false  
#超过30分钟开始关闭空闲连接,由于removeAbandoned为false,这个设置项不再起作用  
removeAbandonedTimeout:1800  
#将当前关闭动作记录到日志,由于removeAbandoned为false,这个设置项不再起作用  
logAbandoned:true  

 

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
    <!-- 给web使用的spring文件 -->  
    <bean id="propertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="locations">  
            <list>  
                <value>/WEB-INF/classes/dbconfig.properties</value>  
            </list>  
        </property>  
    </bean>  
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"  
        destroy-method="close">  
        <property name="url" value="${url}" />  
        <property name="username" value="${username}" />  
        <property name="password" value="${password}" />  
        <property name="driverClassName" value="${driverClassName}" />  
        <property name="filters" value="${filters}" />  
  
        <property name="maxActive" value="${maxActive}" />  
        <property name="initialSize" value="${initialSize}" />  
        <property name="maxWait" value="${maxWait}" />  
        <property name="minIdle" value="${minIdle}" />  
  
        <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />  
        <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />  
  
        <property name="validationQuery" value="${validationQuery}" />  
        <property name="testWhileIdle" value="${testWhileIdle}" />  
        <property name="testOnBorrow" value="${testOnBorrow}" />  
        <property name="testOnReturn" value="${testOnReturn}" />  
        <property name="maxOpenPreparedStatements"  
            value="${maxOpenPreparedStatements}" />  
        <property name="removeAbandoned" value="${removeAbandoned}" /> <!-- 打开removeAbandoned功能 -->  
        <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <!-- 1800秒,也就是30分钟 -->  
        <property name="logAbandoned" value="${logAbandoned}" /> <!-- 关闭abanded连接时输出错误日志 -->  
    </bean>  
      
    <bean id="dataSourceDbcp" class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
  
        <property name="driverClassName" value="${driverClassName}" />  
        <property name="url" value="${url}" />  
        <property name="username" value="${username}" />  
        <property name="password" value="${password}" />  
          
        <property name="maxActive" value="${maxActive}" />  
        <property name="minIdle" value="${minIdle}" />  
        <property name="maxWait" value="${maxWait}" />  
        <property name="defaultAutoCommit" value="true" />  
          
        <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />  
        <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />  
          
        <property name="validationQuery" value="${validationQuery}" />  
        <property name="testWhileIdle" value="${testWhileIdle}" />  
        <property name="testOnBorrow" value="${testOnBorrow}" />  
        <property name="testOnReturn" value="${testOnReturn}" />  
        <property name="maxOpenPreparedStatements"  
            value="${maxOpenPreparedStatements}" />  
        <property name="removeAbandoned" value="${removeAbandoned}" />   
        <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />  
        <property name="logAbandoned" value="${logAbandoned}" />  
    </bean>  
  
      
    <!-- jdbcTemplate -->  
    <bean id="jdbc" class="org.springframework.jdbc.core.JdbcTemplate">  
        <property name="dataSource">  
            <ref bean="dataSource" />  
        </property>  
    </bean>  
      
</beans>  

  配置项中指定了各个参数后,在连接池内部是这么使用这些参数的。数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

  同时连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候可以设置一个testWhileIdle参数为true,注意这里的“while”这个单词应该翻译成“如果”,换句话说testWhileIdle写为testIfIdle更好理解些,其含义为连接在获取连接的时候,如果检测到当前连接不活跃的时间超过了timeBetweenEvictionRunsMillis,则去手动检测一下当前连接的有效性,在保证确实有效后才加以使用。在检测活跃性时,如果当前的活跃时间大于minEvictableIdleTimeMillis,则认为需要关闭当前连接。当然,为了保证绝对的可用性,你也可以使用testOnBorrowtrue(即在每次获取Connection对象时都检测其可用性),不过这样会影响性能。

  最后说一下removeAbandoned参数,其实druid是不能检测到当前使用的连接是否发生了连接泄露,所以在代码内部就假定如果一个连接建立连接的时间很长,则将其认定为泄露,继而强制将其关闭掉。这个参数在druid中默认是不开启的,github上给出的wiki中也对其没有丝毫提及。其实在代码中设置testWhileIdle就能在一定程序上消灭掉泄露的连接,因为如果发生了泄露,那么他的不活跃时间肯定会在某个时间点大于timeBetweenEvictionRunsMillis,继而被回收掉。

 

 

web监控:

web.xml配置如下:

 

<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> 

 

 

打开http://localhost:8080/druid/index.html,会看到监控界面,点击其中的sql标签。

 

posted @ 2015-09-23 10:52  五小瓶  阅读(798)  评论(0)    收藏  举报