前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Druid监控SQL执行状态

使用Druid监控SQL执行状态

作者头像
孟君
发布2019-10-22 14:53:00
6.4K0
发布2019-10-22 14:53:00
举报
文章被收录于专栏:孟君的编程札记

本文使用Druid的连接池替换掉原来的C3P0连接池,然后配置Druid的相关属性,完成对Spring Web工程的JDBC监控。

其实,我采用Druid替换其它连接池,最关键的一个理由是Druid有对SQL执行的监控统计功能。 本文就是来看看看Druid的监控功能。一起玩起来 : )

一、Druid介绍

代码语言:javascript
复制
Druid是一个JDBC组件库,包括数据库连接池、SQL Parser等组件。
DruidDataSource是最好的数据库连接池。
参考Druid wiki上的文章 https://github.com/alibaba/druid/wiki/各种连接池性能对比测试

1.1 Druild包获取

Maven工程中添加druid依赖包:

代码语言:javascript
复制
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.26</version>
    </dependency>

二、Druid使用

2.1 替换C3P0连接池

Web工程原先采用C3P0连接池的配置:

代码语言:javascript
复制
  <!-- 配置数据源-C3PO -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="autoCommitOnClose" value="false" />
        <property name="maxIdleTime" value="${cpool.maxIdleTime}" />
        <property name="checkoutTimeout" value="${cpool.checkoutTimeout}" />
        <property name="initialPoolSize" value="${cpool.minPoolSize}" />
        <property name="minPoolSize" value="${cpool.minPoolSize}" />
        <property name="maxPoolSize" value="${cpool.maxPoolSize}" />
        <property name="acquireIncrement" value="${cpool.acquireIncrement}" />
        <property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}" />
  </bean>

改成Druid连接池DruidDataSource

代码语言:javascript
复制
  <!-- 配置数据源-druid -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
    destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="maxActive" value="20" />
        <property name="initialSize" value="1" />
        <property name="maxWait" value="60000" />
        <property name="minIdle" value="1" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="20" />
  </bean>

2.2 StatViewServlet配置

Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。

这个StatViewServlet的用途包括:

  • 提供监控信息展示的html页面
  • 提供监控信息的JSON API

StatViewServlet是一个标准的javax.servlet.http.HttpServlet,需要配置在你web应用中的WEB-INF/web.xml中。

代码语言:javascript
复制
  <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>

配置完之后,可以通过如下格式的地址在浏览器访问查看。

代码语言:javascript
复制
http:/<host>:<port>/<context>/druid

举个例子:如果host为localhost,port为8080,context为Demo,那么,可以通过如下URL访问。

代码语言:javascript
复制
http://localhost:8080/Demo/druid

那么问题来了?查看的时候,能否提供用户名和密码作为验证呢,而不是直接就能看JDBC执行的状态信息?

答案是肯定的。

代码语言:javascript
复制
需要在上述配置的情况下,配置Servlet的 loginUsername 
和 loginPassword这两个初始参数。

如:

代码语言:javascript
复制
  <servlet>
      <servlet-name>DruidStatView</servlet-name>
      <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
      <init-param>  
            <!-- 用户名 -->  
           <param-name>loginUsername</param-name>  
           <param-value>druid</param-value>  
       </init-param>  
      <init-param>  
           <!-- 密码 -->  
          <param-name>loginPassword</param-name>  
          <param-value>druid</param-value>  
      </init-param>  
  </servlet>
  <servlet-mapping>
      <servlet-name>DruidStatView</servlet-name>
      <url-pattern>/druid/*</url-pattern>
  </servlet-mapping>

配置好之后,登录之后才能访问。

2.3 StatFilter配置

Druid内置提供一个StatFilter用于统计监控信息

如果没有配置StatFilter,那么,我们无法获取相关统计信息。

比如:无法看到SQL监控TAB上的数据。

URI监控TAB中,无法获取JDBC相关的SQL执行信息。

如何展示出这些数据呢? 解决的办法就是配置StatFilter。

StatFilter的别名是stat,在spring中使用别名配置方式如下:

代码语言:javascript
复制
<property name="filters" value="stat" />

将上述stat添加到dataSource中去即可。

代码语言:javascript
复制
  <!-- 配置数据源-druid -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
    destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="filters" value="stat" />
        <property name="maxActive" value="20" />
        <property name="initialSize" value="1" />
        <property name="maxWait" value="60000" />
        <property name="minIdle" value="1" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="20" />
  </bean>

添加完毕之后,再来看一下上述两个TAB ( SQL监控以及 URI监控)下JDBC的内容:

在URI监控页,可以清楚地看到执行某个动作,关联SQL有多少,请求次数、执行时间、并发数等信息。

StatFilter可以和其他的Filter配置使用,比如, 与log4j组合使用。

代码语言:javascript
复制
 <property name="filters" value="stat,log4j" />

这样,我们在点击 “记录日志并重置” 的按钮时,Console中就会输入JDBC相关日志,日志采用JSON的方式记录,如:

代码语言:javascript
复制
[INFO ][2016-11-15 20:11:11,677] com.alibaba.druid.pool.DruidDataSourceStatLoggerImpl.log(DruidDataSourceStatLoggerImpl.java:77) - 
{"url":"jdbc:mysql://127.0.0.1:3306/Demo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull","dbType":"mysql","name":"DataSource-958465974","activeCount":0,"poolingCount":1,"connectCount":0,"closeCount":0}

内置Filter别名和对应的Filter类名如下:

别名

Filter类名

default

com.alibaba.druid.filter.stat.StatFilter

stat

com.alibaba.druid.filter.stat.StatFilter

mergeStat

com.alibaba.druid.filter.stat.MergeStatFilter

encoding

com.alibaba.druid.filter.encoding.EncodingConvertFilter

log4j

com.alibaba.druid.filter.logging.Log4jFilter

log4j2

com.alibaba.druid.filter.logging.Log4j2Filter

slf4j

com.alibaba.druid.filter.logging.Slf4jLogFilter

commonlogging

com.alibaba.druid.filter.logging.CommonsLogFilter

2.4 慢SQL记录

StatFilter属性slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。slowSqlMillis的缺省值为3000,也就是3秒。

代码语言:javascript
复制
<bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
    <property name="slowSqlMillis" value="10000" />
    <property name="logSlowSql" value="true" />
</bean>

在上面的配置中,slowSqlMillis被修改为10秒,并且通过日志输出执行慢的SQL。

slowSqlMillis属性也可以通过connectProperties来配置,例如:

代码语言:javascript
复制
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
      ... ...
      <property name="filters" value="stat" />
      <property name="connectionProperties" value="druid.stat.slowSqlMillis=5000" />
  </bean>

2.5 Wallfilter配置

配置WallFilter,可以起到拦截作用,从而形成SQL的白名单和黑名单。

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

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

代码语言:javascript
复制
  deny-variant.txt
  deny-schema.txt
  deny-function.txt
  permit-variant.txt
  permit-variant.txt

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

代码语言:javascript
复制
  <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>

本文实例中,采用如下的配置:

代码语言:javascript
复制
  <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>

  <!-- 配置数据源-druid -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
    destroy-method="close">
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="filters" value="stat" />
    <property name="maxActive" value="20" />
    <property name="initialSize" value="1" />
    <property name="maxWait" value="60000" />
    <property name="minIdle" value="1" />
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    <property name="minEvictableIdleTimeMillis" value="300000" />
    <property name="testWhileIdle" value="true" />
    <property name="testOnBorrow" value="false" />
    <property name="testOnReturn" value="false" />
    <property name="poolPreparedStatements" value="true" />
    <property name="maxOpenPreparedStatements" value="20" />
    <property name="proxyFilters">
      <list>
        <ref bean="wall-filter" />
      </list>
    </property>
  </bean>

配置好Wallfilter, 我们就可以看到SQL防火墙 TAB下的内容了。

因为是默认状态,没有配置任何拦截的属性信息,所以,SQL的执行都在白名单中展示出来了。

2.6 配置Spring和jdbc的关联

最后,还有一个Tab的内容没有展示,那就是Spring监控

代码语言:javascript
复制
Druid提供了Spring和Jdbc的关联监控。

本文在Spring的applicationContext.xml配置文件中配置如下信息,支持方法名的拦截。

代码语言:javascript
复制
  <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.demo.mybatis.auto.*</value>
        <value>com.demo.mybatis.manual.*</value>
      </list>
    </property>
  </bean>
  <aop:config>
    <aop:advisor advice-ref="druid-stat-interceptor"
      pointcut-ref="druid-stat-pointcut" />
  </aop:config>

完工后,我们再去看一下,Spring监控的TAB内容,就可以看到相关的MyBatis Mapper执行信息。

在Spring监控页,可以显示相关DAO执行的方法,方法执行的次数、执行的时间等信息。

三、小结

通过上述几个部分的配置,监控页面上所有的TAB都可以查看信息了。

当然,Druid还有很多其他的功能,在这篇文章中就一一展示,有兴趣的朋友可以在Druid的Github网页上查看。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Druid介绍
    • 1.1 Druild包获取
    • 二、Druid使用
      • 2.1 替换C3P0连接池
        • 2.2 StatViewServlet配置
          • 2.3 StatFilter配置
            • 2.5 Wallfilter配置
            • 三、小结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档