zoukankan      html  css  js  c++  java
  • Druid连接池(二)

    六、Druid关联

      6.1、Web关联监控配置

      WebStatFilter用于采集web-jdbc关联监控的数据。

      web.xml配置:

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

      exlusions配置:

      经常需要排除一些不必要的url,比如.js,/jslib/等等。配置在init-param中。比如:

    <init-param>        
        <param-name>exclusions</param-name>
        <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
    </init-param>

      sessionStatMaxCount配置:  

      缺省sessionStatMaxCount是1000个。你可以按需要进行配置,比如:

    <init-param>        
        <param-name>sessionStatMaxCount</param-name>
        <param-value>1000</param-value>
    </init-param>

      sessionStatEnable配置:

      你可以关闭session统计功能,比如:

    <init-param>        
        <param-name>sessionStatEnable</param-name>
        <param-value>false</param-value>
    </init-param>

      principalSessionName配置:

      你可以配置principalSessionName,使得druid能够知道当前的session的用户是谁。比如:

    <init-param>        
        <param-name>principalSessionName</param-name>
        <param-value>xxx.user</param-value>
    </init-param>

      根据需要,把其中的xxx.user修改为你user信息保存在session中的sessionName。

      注意:如果你session中保存的是非string类型的对象,需要重载toString方法。

      principalCookieName:

      如果你的user信息保存在cookie中,你可以配置principalCookieName,使得druid知道当前的user是谁

    <init-param>        
        <param-name>principalCookieName</param-name>
        <param-value>xxx.user</param-value>
    </init-param>

      根据需要,把其中的xxx.user修改为你user信息保存在cookie中的cookieName

      profileEnable:

      druid 0.2.7版本开始支持profile,配置profileEnable能够监控单个url调用的sql列表。

    <init-param>    
        <param-name>profileEnable</param-name>
        <param-value>true</param-value>
    </init-param>

      6.2.Spring关联监控配置 

       Druid提供了Spring和Jdbc的关联监控。

       配置spring

    com.alibaba.druid.support.spring.stat.DruidStatInterceptor是一个标准的Spring MethodInterceptor。

      灵活进行AOP配置。

          Spring AOP的配置文档: 

     http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop-api.html

       按类型拦截配置:

    <bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
    </bean>
    <bean id="druid-type-proxyCreator" class="com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator">
        <!-- 所有ABCInterface的派生类被拦截监控 -->
        <property name="targetBeanType" value="xxxx.ABCInterface" />
        <property name="interceptorNames">
          <list>
            <value>druid-stat-interceptor</value>
          </list>
        </property>
    </bean>

      方法名正则匹配拦截配置:

    <bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
    </bean>
    <bean id="druid-stat-pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">
        <property name="patterns">
          <list>
             <value>com.mycompany.service.*</value>
             <value>com.mycompany.dao.*</value>
          </list>
        </property>
    </bean>
    <aop:config>
        <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
    </aop:config>

      有些情况下,可能你需要配置proxy-target-class,例如:

    <aop:config proxy-target-class="true">    
        <aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut" />
    </aop:config>

      按照BeanId来拦截配置:

    <bean id="druid-stat-interceptor"    class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">  
    </bean> 
    <bean    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">    
        <property name="proxyTargetClass" value="true" />    
        <property name="beanNames">        
          <list>            
            <!-- 这里配置需要拦截的bean id列表 -->            
            <value>xxx-dao</value>            
            <value>xxx-service</value>        
          </list>    
        </property>    
        <property name="interceptorNames">        
          <list>            
            <value>druid-stat-interceptor</value>        
          </list>    
        </property>
    </bean>

    七、Druid防御

      Druid提供了WallFilter,它是基于SQL语义分析来实现防御SQL注入攻击的。

      这个文档提供基于Spring的各种配置方式。

      使用缺省配置的WallFilter:

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
        ...
        <property name="filters" value="wall"/>
    </bean>

      结合其他Filter一起使用:

          WallFilter可以结合其他Filter一起使用,例如:

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
        ...
        <property name="filters" value="wall,stat"/>
    </bean>

      这样,拦截检测的时间不在StatFilter统计的SQL执行时间内。

      如果希望StatFilter统计的SQL执行时间内,则使用如下配置:

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">      
        ...
        <property name="filters" value="stat,wall"/>
    </bean>

      指定dbType

         有时候,一些应用框架做了自己的JDBC Proxy Driver,是的DruidDataSource无法正确识别数据库的类型,则需要特别指定,如下:

    <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">      
        <property name="dbType" value="mysql" />
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        ...
        <property name="proxyFilters">
          <list>
            <ref bean="wall-filter"/>
          </list>
        </property>
    </bean>

      指定配置装载的目录

      缺省情况下,配置装载的目录如下:

    数据库类型

    目录

    mysql

    META-INF/druid/wall/mysql

    oracle

    META-INF/druid/wall/oracle

    sqlserver

    META-INF/druid/wall/sqlserver

    postgres

    META-INF/druid/wall/postgres

      从配置目录中以下文件中读取配置:

        deny-variant.txt  deny-schema.txt  deny-function.txt  deny-table.txt  deny-object.txt

      指定配置装载的目录是可以指定,例如:

    <bean id="wall-filter-config" class="com.alibaba.druid.wall.WallConfig" init-method="init">      
        <!-- 指定配置装载的目录 -->
        <property name="dir" value="META-INF/druid/wall/mysql" />
    </bean>
    <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">
        <property name="dbType" value="mysql" />
        <property name="config" ref="wall-filter-config" />
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        ...
        <property name="proxyFilters">
            <list>
                <ref bean="wall-filter"/>
            </list>
        </property>
    </bean>

    WallConfig详细说明

    本身的配置

    配置项

    缺省值

    dir

    按照dbType分别配置: 
    mysql : META-INF/druid/wall/mysql 
    oracle : META-INF/druid/wall/oracle 
    sqlserver : META-INF/druid/wall/sqlserver 

    拦截配置-语句

    配置项

    缺省值

    描述

    selelctAllow

    true

    是否允许执行SELECT语句

    selectAllColumnAllow

    true

    是否允许执行SELECT * FROM T这样的语句。如果设置为false,不允许执行select * from t,但select * from (select id, name from t) a。这个选项是防御程序通过调用select *获得数据表的结构信息。

    selectIntoAllow

    true

    SELECT查询中是否允许INTO字句

    deleteAllow

    true

    是否允许执行DELETE语句

    updateAllow

    true

    是否允许执行UPDATE语句

    insertAllow

    true

    是否允许执行INSERT语句

    replaceAllow

    true

    是否允许执行REPLACE语句

    mergeAllow

    true

    是否允许执行MERGE语句,这个只在Oracle中有用

    callAllow

    true

    是否允许通过jdbc的call语法调用存储过程

    setAllow

    true

    是否允许使用SET语法

    truncateAllow

    true

    truncate语句是危险,缺省打开,若需要自行关闭

    createTableAllow

    true

    是否允许创建表

    alterTableAllow

    true

    是否允许执行Alter Table语句

    dropTableAllow

    true

    是否允许修改表

    commentAllow

    false

    是否允许语句中存在注释,Oracle的用户不用担心,Wall能够识别hints和注释的区别

    noneBaseStatementAllow

    false

    是否允许非以上基本语句的其他语句,缺省关闭,通过这个选项就能够屏蔽DDL。

    multiStatementAllow

    false

    是否允许一次执行多条语句,缺省关闭

    useAllow

    true

    是否允许执行mysql的use语句,缺省打开

    describeAllow

    true

    是否允许执行mysql的describe语句,缺省打开

    showAllow

    true

    是否允许执行mysql的show语句,缺省打开

    commitAllow

    true

    是否允许执行commit操作

    rollbackAllow

    true

    是否允许执行roll back操作

    如果把selectIntoAllow、deleteAllow、updateAllow、insertAllow、mergeAllow都设置为false,这就是一个只读数据源了。

    拦截配置-永真条件

    配置项

    缺省值

    描述

    selectWhereAlwayTrueCheck

    true

    检查SELECT语句的WHERE子句是否是一个永真条件

    selectHavingAlwayTrueCheck

    true

    检查SELECT语句的HAVING子句是否是一个永真条件

    deleteWhereAlwayTrueCheck

    true

    检查DELETE语句的WHERE子句是否是一个永真条件

    deleteWhereNoneCheck

    false

    检查DELETE语句是否无where条件,这是有风险的,但不是SQL注入类型的风险

    updateWhereAlayTrueCheck

    true

    检查UPDATE语句的WHERE子句是否是一个永真条件

    updateWhereNoneCheck

    false

    检查UPDATE语句是否无where条件,这是有风险的,但不是SQL注入类型的风险

    conditionAndAlwayTrueAllow

    false

    检查查询条件(WHERE/HAVING子句)中是否包含AND永真条件

    conditionAndAlwayFalseAllow

    false

    检查查询条件(WHERE/HAVING子句)中是否包含AND永假条件

    conditionLikeTrueAllow

    true

    检查查询条件(WHERE/HAVING子句)中是否包含LIKE永真条件

    其他拦截配置

    配置项

    缺省值

    描述

    selectIntoOutfileAllow

    false

    SELECT ... INTO OUTFILE 是否允许,这个是mysql注入攻击的常见手段,缺省是禁止的

    selectUnionCheck

    true

    检测SELECT UNION

    selectMinusCheck

    true

    检测SELECT MINUS

    selectExceptCheck

    true

    检测SELECT EXCEPT

    selectIntersectCheck

    true

    检测SELECT INTERSECT

    mustParameterized

    false

    是否必须参数化,如果为True,则不允许类似WHERE ID = 1这种不参数化的SQL

    strictSyntaxCheck

    true

    是否进行严格的语法检测,Druid SQL Parser在某些场景不能覆盖所有的SQL语法,出现解析SQL出错,可以临时把这个选项设置为false,同时把SQL反馈给Druid的开发者。

    conditionOpXorAllow

    false

    查询条件中是否允许有XOR条件。XOR不常用,很难判断永真或者永假,缺省不允许。

    conditionOpBitwseAllow

    true

    查询条件中是否允许有"&"、"~"、"|"、"^"运算符。

    conditionDoubleConstAllow

    false

    查询条件中是否允许连续两个常量运算表达式

    minusAllow

    true

    是否允许SELECT * FROM A MINUS SELECT * FROM B这样的语句

    intersectAllow

    true

    是否允许SELECT * FROM A INTERSECT SELECT * FROM B这样的语句

    constArithmeticAllow

    true

    拦截常量运算的条件,比如说WHERE FID = 3 - 1,其中"3 - 1"是常量运算表达式。

    limitZeroAllow

    false

    是否允许limit 0这样的语句

    禁用对象检测配置

    配置项

    缺省值

    描述

    tableCheck

    true

    检测是否使用了禁用的表

    schemaCheck

    true

    检测是否使用了禁用的Schema

    functionCheck

    true

    检测是否使用了禁用的函数

    objectCheck

    true

    检测是否使用了“禁用对对象”

    variantCheck

    true

    检测是否使用了“禁用的变量”

    readOnlyTables

    指定的表只读,不能够在SELECT INTO、DELETE、UPDATE、INSERT、MERGE中作为"被修改表"出现

    Jdbc相关配置

    配置项

    缺省值

    描述

    metadataAllow

    true

    是否允许调用Connection.getMetadata方法,这个方法调用会暴露数据库的表信息

    wrapAllow

    true

    是否允许调用Connection/Statement/ResultSet的isWrapFor和unwrap方法,这两个方法调用,使得有办法拿到原生驱动的对象,绕过WallFilter的检测直接执行SQL。

    WallFiler配置说明

    配置项

    缺省值

    描述

    logViolation

    false

    对被认为是攻击的SQL进行LOG.error输出

    throwException

    true

    对被认为是攻击的SQL抛出SQLExcepton

    config

    provider

      刚开始引入WallFilter的时候,把logViolation设置为true,而throwException设置为false。就可以观察是否存在违规的情况,同时不影响业务运行。

    八、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_user}" />
        <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" />

        <property name="validationQuery" value="SELECT 'x'" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />

        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat" />
    </bean>

      通常来说,只需要修改initialSize、minIdle、maxActive。

      如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。分库分表较多的数据库,建议配置为false。

    十、Druid日志

      Druid提供了Log4jFilter、CommonsLogFilter和Slf4jFilter,具体配置看这里:

         Druid内置提供了三种LogFilter(Log4jFilter、CommonsLogFilter、Slf4jLogFilter),用于输出JDBC执行的日志。这些Filter都是Filter-Chain扩展机制中的Filter,所以配置方式可以参考这里:Filter配置

      10.1、别名映射

      在druid-xxx.jar!/META-INF/druid-filter.properties文件中描述了这三种Filter的别名

    druid.filters.log4j=com.alibaba.druid.filter.logging.Log4jFilter  
    druid.filters.slf4j=com.alibaba.druid.filter.logging.Slf4jLogFilter
    druid.filters.commonlogging=com.alibaba.druid.filter.logging.CommonsLogFilter
    druid.filters.commonLogging=com.alibaba.druid.filter.logging.CommonsLogFilter

      他们的别名分别是log4j、slf4j、commonlogging和commonLogging。其中commonlogging和commonLogging只是大小写不同。

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"      init-method="init" destroy-method="close">      
        ... ...
        <property name="filters" value="stat,log4j" />
    </bean>

      10.2、loggerName映射

       LogFilter都是缺省使用四种不同的Logger执行输出,看实现代码:
    public abstract class LogFilter {      
        protected String dataSourceLoggerName = "druid.sql.DataSource";
        protected String connectionLoggerName = "druid.sql.Connection";
        protected String statementLoggerName = "druid.sql.Statement";
        protected String resultSetLoggerName = "druid.sql.ResultSet";
    }
      你可以根据你的需要修改,在log4j.properties文件上做配置时,注意配置使用相关的logger。 

      10.3、配置输出日志

       缺省输入的日志信息全面,但是内容比较多,有时候我们需要定制化配置日志输出。

    <bean id="log-filter" class="com.alibaba.druid.filter.logging.Log4jFilter">    
        <property name="resultSetLogEnabled" value="false" />
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        ...
        <property name="proxyFilters">
          <list>
              <ref bean="log-filter"/>
          </list>
        </property>
    </bean>

    参数

    说明

    dataSourceLogEnabled

    所有DataSource相关的日志

    connectionLogEnabled

    所有连接相关的日志

    connectionLogErrorEnabled

    所有连接上发生异常的日志

    statementLogEnabled

    所有Statement相关的日志

    statementLogErrorEnabled

    所有Statement发生异常的日志

    resultSetLogEnabled

    resultSetLogErrorEnabled

    connectionConnectBeforeLogEnabled

    connectionConnectAfterLogEnabled

    connectionCommitAfterLogEnabled

    connectionRollbackAfterLogEnabled

    connectionCloseAfterLogEnabled

    statementCreateAfterLogEnabled

    statementPrepareAfterLogEnabled

    statementPrepareCallAfterLogEnabled

    statementExecuteAfterLogEnabled

    statementExecuteQueryAfterLogEnabled

    statementExecuteUpdateAfterLogEnabled

    statementExecuteBatchAfterLogEnabled

    statementCloseAfterLogEnabled

    statementParameterSetLogEnabled

    resultSetNextAfterLogEnabled

    resultSetOpenAfterLogEnabled

    resultSetCloseAfterLogEnabled

      10.4、log4j.properties配置

      如果你使用log4j,可以通过log4j.properties文件配置日志输出选项,例如:

    log4j.logger.druid.sql=warn,stdout  
    log4j.logger.druid.sql.DataSource=warn,stdout
    log4j.logger.druid.sql.Connection=warn,stdout
    log4j.logger.druid.sql.Statement=warn,stdout
    log4j.logger.druid.sql.ResultSet=warn,stdout

      10.5、输出可执行的SQL

      Java启动参数配置方式

    -Ddruid.log.stmt.executableSql=true

      logFilter参数直接配置

    <bean id="log-filter" class="com.alibaba.druid.filter.logging.Log4jFilter">        
        <property name="statementExecutableSqlLogEnable" value="true" />
    </bean>

    十一、Druid泄露

      Druid提供了多种监测连接泄漏的手段

      连接泄漏监测

         当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏了。Druid提供了RemoveAbandanded相关配置,用来关闭长时间不使用的连接。例如:

      配置

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">    
        ... ...
        <property name="removeAbandoned" value="true" />
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandonedTimeout" value="1800" />
        <!-- 1800秒,也就是30分钟 -->
        <property name="logAbandoned" value="true" />
        <!-- 关闭abanded连接时输出错误日志 -->
        ... ...
    </bean>

      配置removeAbandoned对性能会有一些影响,建议怀疑存在泄漏之后再打开。在上面的配置中,如果连接超过30分钟未关闭,就会被强行回收,并且日志记录连接申请时的调用堆栈。

      内置监控页面查看未关闭连接堆栈信息

         当removeAbandoned=true之后,可以在内置监控界面datasource.html中的查看ActiveConnection StackTrace属性的,可以看到未关闭连接的具体堆栈信息,从而方便查出哪些连接泄漏了。

      web应用

         如果你的应用配置了WebStatFilter 
         在内置监控页面weburi-detail.html中,查看JdbcPoolConnectionOpenCount和JdbcPoolConnectionCloseCount属性,如果不相等,就是泄漏了。

  • 相关阅读:
    POI_Excel表格数据导入导出实例--支持xls/xlsx格式
    js图片压缩工具---base64码上传插件,兼容h5和微信端(lrz.mobile.min.js)
    同一个页面,加载不同版本jQuery
    This method isn't transactional
    jquery.cookie的使用,记住用户名
    正则表达式 2017/6/12
    kSet 2017/6/6
    差分与二维差分
    求组合数
    高精度
  • 原文地址:https://www.cnblogs.com/javahr/p/8365209.html
Copyright © 2011-2022 走看看