Druid是阿里巴巴的一个开源项目,据该网站称:Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

        上述内容难免有水分,但是如果真如他所说Druid已经在阿里巴巴和淘宝等大型网站及系统上被充分使用及测试的话,那么Druid还是值得信赖的,毕竟任何有信誉公司不会拿这个去开玩笑。

 

        Druid官网:http://code.alibabatech.com/wiki/display/Druid/Home

 

        Druid有以下几点优势或好处:

  • 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  • 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

        看到上面的这些Druid的好处你是否已经心动了?下面就让我们一起来实验一下。

 

        1.下载Druid(http://code.alibabatech.com/mvn/releases/com/alibaba/druid/),目前Druid最新版本为0.2.23,可以选择源码,javadoc,jar等。

        2.还是在之前举例的项目基础上添加Druid代码,代码其实很简单,把之前的c3p0改改就能用:

/**
 * Druid
 */
public void getUsrInfoWithDruid(Integer usrId) {
    String sql="SELECT * FROM USER u WHERE u.USR_ID=" + usrId;

    try {
        //通过Map方式设置Druid参数
        Map<String, String> druidMap=new HashMap<String, String>();
        druidMap.put(DruidDataSourceFactory.PROP_USERNAME, user);
        druidMap.put(DruidDataSourceFactory.PROP_PASSWORD, passwd);
        druidMap.put(DruidDataSourceFactory.PROP_URL, jdbcUrl);
        druidMap.put(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, driver);
        //通过DruidDataSourceFactory获取DataSource实例
        dataSource=DruidDataSourceFactory.createDataSource(druidMap);
        conn=dataSource.getConnection();
        Statement st=conn.createStatement();
        ResultSet result=st.executeQuery(sql);
        while(result.next()) {
            System.out.println("Druid:begin");
            System.out.println("Name:" + result.getString("NAME"));
            System.out.println("Druid:end");
        }
        result.close();
        st.close();
        conn.close();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

 

        以上是利用Map方式向Druid传递参数,这种方式基本上用不到。

 

        3.利用属性文件传递参数:

 



#MySQL驱动 druid.driverClassName=com.mysql.jdbc.Driver #MySQL连接地址 druid.url=jdbc\:mysql\://192.168.0.8\:3306/test #数据库用户 druid.username=moster #该用户密码 druid.password=shzygjrmdwg #自动提交 druid.defaultAutoCommit=false #只读设置 druid.defaultReadOnly=false druid.defaultTransactionIsolation= druid.defaultCatalog= #连接池最大使用连接数量 druid.maxActive=25 #连接池最大空闲 druid.maxIdle=25 #连接池最小空闲 druid.minIdle=1 #初始化连接池大小 druid.initialSize=1 #连接等待时间,默认:-1 druid.maxWait=3000 druid.testOnBorrow= druid.testOnReturn= #检测间隔,检测需要关闭的空闲连接,单位:毫秒 druid.timeBetweenEvictionRunsMillis= druid.numTestsPerEvictionRun= #一个连接在池中最小生存的时间,单位:毫秒 druid.minEvictableIdleTimeMillis= druid.testWhileIdle= #测试SQL druid.validationQuery= #测试超时时间 druid.validationQueryTimeout= #初始化连接SQL druid.initConnectionSqls= druid.accessToUnderlyingConnectionAllowed= #移除被废弃连接 druid.removeAbandoned= #超时时间 druid.removeAbandonedTimeout= #日志记录 druid.logAbandoned= #PreparedStatements druid.poolPreparedStatements= #PreparedStatement最大数量 druid.maxOpenPreparedStatements= #属性配置文件 druid.connectionProperties= #filters配置 druid.filters= #Exception处理 druid.exceptionSorter= #Exception处理类名 druid.exception-sorter-class-name= #初始化 druid.init=



 

        官网居然连这些属性的解释都没有,以上是我自己翻译的,如有偏差请及时指正。


 

        4.将原创建DataSource方法修改为:

Properties p=new Properties();
p.load(getClass().getResourceAsStream("/druid.properties"));
//通过属性文件设置Druid参数
dataSource=DruidDataSourceFactory.createDataSource(p);

        Druid的参数可以参考DruidDataSourceFactory类的源码,其中参数的命名规则与c3p0,DBCP非常像,也比较容易理解,以下是具体参数:

String    PROP_DEFAULTAUTOCOMMIT                   = "defaultAutoCommit";
String    PROP_DEFAULTREADONLY                     = "defaultReadOnly";
String    PROP_DEFAULTTRANSACTIONISOLATION         = "defaultTransactionIsolation";
String    PROP_DEFAULTCATALOG                      = "defaultCatalog";
String    PROP_DRIVERCLASSNAME                     = "driverClassName";
String    PROP_MAXACTIVE                           = "maxActive";
String    PROP_MAXIDLE                             = "maxIdle";
String    PROP_MINIDLE                             = "minIdle";
String    PROP_INITIALSIZE                         = "initialSize";
String    PROP_MAXWAIT                             = "maxWait";
String    PROP_TESTONBORROW                        = "testOnBorrow";
String    PROP_TESTONRETURN                        = "testOnReturn";
String    PROP_TIMEBETWEENEVICTIONRUNSMILLIS       = "timeBetweenEvictionRunsMillis";
String    PROP_NUMTESTSPEREVICTIONRUN              = "numTestsPerEvictionRun";
String    PROP_MINEVICTABLEIDLETIMEMILLIS          = "minEvictableIdleTimeMillis";
String    PROP_TESTWHILEIDLE                       = "testWhileIdle";
String    PROP_PASSWORD                            = "password";
String    PROP_URL                                 = "url";
String    PROP_USERNAME                            = "username";
String    PROP_VALIDATIONQUERY                     = "validationQuery";
String    PROP_VALIDATIONQUERY_TIMEOUT             = "validationQueryTimeout";
String    PROP_INITCONNECTIONSQLS                  = "initConnectionSqls";
String    PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
String    PROP_REMOVEABANDONED                     = "removeAbandoned";
String    PROP_REMOVEABANDONEDTIMEOUT              = "removeAbandonedTimeout";
String    PROP_LOGABANDONED                        = "logAbandoned";
String    PROP_POOLPREPAREDSTATEMENTS              = "poolPreparedStatements";
String    PROP_MAXOPENPREPAREDSTATEMENTS           = "maxOpenPreparedStatements";
String    PROP_CONNECTIONPROPERTIES                = "connectionProperties";
String    PROP_FILTERS                             = "filters";
String    PROP_EXCEPTION_SORTER                    = "exceptionSorter";
String    PROP_EXCEPTION_SORTER_CLASS_NAME         = "exception-sorter-class-name";
String    PROP_INIT                                = "init";

 

        Druid监控:

        同Proxool一样Druid也提供了监控功能,而且更强大!

        Druid的监控配置起来跟Proxool类似,其实我的感觉就是Druid把现在主流的连接池优点结合起来了,很有中国人做东西的“风格”。



<!-- Druid监控Servlet --> <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>



 

        打开浏览器就可以看到监控页面了。


       下图是Druid官网给出的几种连接池的对比表格,从数据上来看Druid在各方面都占有很大的优势,实际情况还需要实践去检验。

java 数据库连接池的好处 java druid数据库连接池_数据库


 

 

        LRU
        LRU是一个性能关键指标,特别Oracle,每个Connection对应数据库端的一个进程,如果数据库连接池遵从LRU,有助于数据库服务器优化,这是重要的指标。在测试中,Druid、DBCP、Proxool、JBoss是遵守LRU的。BoneCP、C3P0则不是。BoneCP在mock环境下性能可能好,但在真实环境中则就不好了。

 

        PSCache
        PSCache是数据库连接池的关键指标。在Oracle中,类似SELECT NAME FROM USER WHERE ID = ?这样的SQL,启用PSCache和不启用PSCache的性能可能是相差一个数量级的。Proxool是不支持PSCache的数据库连接池,如果你使用Oracle、SQL Server、DB2、Sybase这样支持游标的数据库,那你就完全不用考虑Proxool。

 

        PSCache-Oracle-Optimized
        Oracle 10系列的Driver,如果开启PSCache,会占用大量的内存,必须做特别的处理,启用内部的EnterImplicitCache等方法优化才能够减少内存的占用。这个功能只有DruidDataSource有。如果你使用的是Oracle Jdbc,你应该毫不犹豫采用DruidDataSource。

 

        ExceptionSorter
        ExceptionSorter是一个很重要的容错特性,如果一个连接产生了一个不可恢复的错误,必须立刻从连接池中去掉,否则会连续产生大量错误。这个特性,目前只有JBossDataSource和Druid实现。Druid的实现参考自JBossDataSource。

 

        监控
        DruidDataSource自身提供有NotEmptyWaitCount、PSCahcheHitCount等有用的监控属性,通过配置StatFilter能够监控SQL的执行情况。

 

        扩展
        DruidDataSource提供基于Filter-Chain模式的模式的扩展。