本文使用Druid的鏈接池替換掉原來的C3P0鏈接池,而後配置Druid的相關屬性,完成對spring web工程的JDBC監控。html
其實,我採用Druid替換其它鏈接池,最關鍵的一個理由是Druid有對SQL執行的監控統計功能。 :)java
本文就是來看看看Druid的監控功能。~~~ 一塊兒玩起來 : )mysql
Druid是一個JDBC組件庫,包括數據庫鏈接池、SQL Parser等組件。DruidDataSource是最好的數據庫鏈接池。參考Druid wiki上的文章 <<各鏈接池的性能比較>>git
Maven工程中添加druid依賴包:github
<!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.26</version> </dependency>
Web工程原先採用C3P0鏈接池的配置:web
<!-- 配置數據源-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鏈接池DruidDataSourcespring
<!-- 配置數據源-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>
Druid內置提供了一個StatViewServlet用於展現Druid的統計信息。sql
這個StatViewServlet的用途包括:數據庫
- 提供監控信息展現的html頁面
- 提供監控信息的JSON API
StatViewServlet是一個標準的javax.servlet.http.HttpServlet,須要配置在你web應用中的WEB-INF/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:/<host>:<port>/<context>/druid
舉個例子:
若是host爲localhost,port爲8080,context爲Demo,那麼,能夠經過以下URL訪問。
http://localhost:8080/Demo/druid
那麼問題來了
查看的時候,可否提供用戶名和密碼做爲驗證呢,而不是直接就能看JDBC執行的狀態信息?
答案是確定的。
須要在上述配置的狀況下,配置Servlet的
loginUsername
和loginPassword
這兩個初始參數。
如:
<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>
配置好以後,登陸以後才能訪問。
Druid內置提供一個StatFilter,用於統計監控信息。
若是沒有配置StatFilter,那麼,咱們沒法獲取相關統計信息。
好比:
沒法看到SQL監控TAB上的數據。
URI監控TAB中,沒法獲取JDBC相關的SQL執行信息。
如何展現出這些數據呢? 解決的辦法就是配置StatFilter。
StatFilter的別名是stat,在spring中使用別名配置方式以下:
<property name="filters" value="stat" />
將上述stat添加到dataSource中去便可。
<!-- 配置數據源-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的內容:
在SQL監控頁面,能夠很清楚地看到目前執行SQL的具體狀況,包括某條SQL語句執行的時間(平均、最慢)、SQL執行次數、SQL執行出錯的次數等。這些信息,能夠做爲系統SQL語句優化的一個指標。
在URI監控頁,能夠清楚地看到執行某個動做,關聯SQL有多少,請求次數、執行時間、併發數等信息。
StatFilter能夠和其餘的Filter配置使用,好比, 與log4j組合使用。
<property name="filters" value="stat,log4j" />
這樣,咱們在點擊 「記錄日誌並重置」 的按鈕時,Console中就會輸入JDBC相關日誌,日誌採用JSON的方式記錄,如:
[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
StatFilter屬性slowSqlMillis用來配置SQL慢的標準,執行時間超過slowSqlMillis的就是慢。slowSqlMillis的缺省值爲3000,也就是3秒。
<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來配置,例如:
<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>
配置WallFilter,能夠起到攔截做用,從而造成SQL的白名單和黑名單。
缺省狀況下,配置裝載的目錄以下:
數據庫類型 目錄 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 permit-variant.txt permit-variant.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>
本文實例中,採用以下的配置:
<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的執行都在白名單中展現出來了。
最後,還有一個Tab的內容沒有展現,那就是Spring監控。
Druid提供了Spring和Jdbc的關聯監控。
本文在Spring的applicationContext.xml配置文件中配置以下信息,支持方法名的攔截。
<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網頁上查看。