Spring AOP监控SQL执行

 对数据库连接池Proxool比较熟悉的读者,都知道Proxool可以记录SQL执行内容和时间等信息日志。我们可以将该日志记录专门的SQL日志文件,对于查找执行特别耗时的SQL起了不小的作用。对于一些其他连接池,没有该特性时,本文介绍Spring AOP切面方法来记录SQL日志。

当然也可以通过数据库提供的特性来查询执行效率较低的SQL,本文不做探讨。

 

         本文介绍使用SpringJdbcTemplate执行SQL,使用其他方法或者ORM思路类似(Hibernate提供了日志记录功能)。

 

         使用AOP,可以使用Around通知,在JdbcTemplate执行方法前,记录当前时间,在方法执行完后,计算SQL耗时,并记录日志。思路很简单,不过多介绍,代码如下。


[java]  view plain  copy
  1. package org.enyes.sql.util;  
  2. import org.apache.log4j.Logger;  
  3. import org.aspectj.lang.ProceedingJoinPoint;  
  4. import org.aspectj.lang.annotation.Around;  
  5. import org.aspectj.lang.annotation.Aspect;  
  6.   
  7. /** 
  8.  * 对Spring JdbcTemplate进行切面,记录每个sql执行时间。 
  9.  */  
  10. @Aspect  
  11. public class SqlExecutionTimeAspect {  
  12.     /** 
  13.      * logger 
  14.      */  
  15.     private static final Logger LOG = Logger  
  16.             .getLogger(SqlExecutionTimeAspect.class);  
  17.   
  18.     /** 
  19.      * 当Sql执行时间超过该值时,则进行log warn级别题型,否则记录INFO日志。 
  20.      */  
  21.     private long warnWhenOverTime = 2 * 60 * 1000L;  
  22.   
  23.     @Around("execution(* org.springframework.jdbc.core.JdbcTemplate.*(..))")  
  24.     public Object logSqlExecutionTime(ProceedingJoinPoint joinPoint)  
  25.             throws Throwable {  
  26.         long startTime = System.currentTimeMillis();  
  27.         Object result = joinPoint.proceed();  
  28.         long costTime = System.currentTimeMillis() - startTime;  
  29.         if (costTime > warnWhenOverTime) {  
  30.             StringBuilder sb = new StringBuilder();  
  31.             sb.append("execute method :").append(joinPoint.getSignature());  
  32.             sb.append("args: ").append(arrayToString(joinPoint.getArgs()));  
  33.             sb.append(" cost time[").append(costTime).append("]ms");  
  34.             LOG.warn(sb);  
  35.         } else if (LOG.isInfoEnabled()) {  
  36.             StringBuilder sb = new StringBuilder();  
  37.             sb.append("execute method :").append(joinPoint.getSignature());  
  38.             sb.append("args: ").append(arrayToString(joinPoint.getArgs()));  
  39.             sb.append(" cost time[").append(costTime).append("]ms");  
  40.             LOG.info(sb);  
  41.         }  
  42.         return result;  
  43.     }  
  44.   
  45.     private static String arrayToString(Object[] a) {  
  46.         if (a == null)  
  47.             return "null";  
  48.   
  49.         int iMax = a.length - 1;  
  50.         if (iMax == -1)  
  51.             return "[]";  
  52.   
  53.         StringBuilder b = new StringBuilder();  
  54.         b.append('[');  
  55.         for (int i = 0;; i++) {  
  56.             if (a[i] instanceof Object[]) {  
  57.                 b.append(arrayToString((Object[]) a[i]));  
  58.             } else {  
  59.                 b.append(String.valueOf(a[i]));  
  60.             }  
  61.             if (i == iMax)  
  62.                 return b.append(']').toString();  
  63.             b.append(", ");  
  64.         }  
  65.     }  
  66. }  

Springxml配置如下:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xmlns:task="http://www.springframework.org/schema/task"   
  8.     xsi:schemaLocation="    
  9.     http://www.springframework.org/schema/beans     
  10.     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
  11.     http://www.springframework.org/schema/context    
  12.     http://www.springframework.org/schema/context/spring-context-3.1.xsd    
  13.     http://www.springframework.org/schema/mvc    
  14.     http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd   
  15.      http://www.springframework.org/schema/tx   
  16.     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd   
  17.      http://www.springframework.org/schema/aop  
  18.     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd    
  19.     http://www.springframework.org/schema/task   
  20.     http://www.springframework.org/schema/task/spring-task-3.1.xsd   
  21. ">  
  22. <beans>  
  23. <aop:aspectj-autoproxy proxy-target-class="true"/>  
  24. <bean class="org.enyes.sql.util.SqlExecutionTimeAspect"/>  
  25. </beans>  

可以使用Log4J将SqlExecutionTimeAspect类的日志打印到专门的日志中,并且warnWhenOverTime提供setter方法,可以通过Spring xml来具体配置。

完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值