功能
1.定期统计每个SQL的执行次数,平均执行时间和平均返回行数,并且打印在日志中
2.如果有慢SQL或者返回行数很多的SQL,直接在日志中打印详细信息.
maven依赖
-
<dependencies>
-
<dependency>
-
<groupId>org.softee</groupId>
-
<artifactId>pojo-mbean</artifactId>
-
<version>1.1</version>
-
</dependency>
-
<dependency>
-
<groupId>commons-codec</groupId>
-
<artifactId>commons-codec</artifactId>
-
<version>1.9</version>
-
</dependency>
-
<dependency>
-
<groupId>org.slf4j</groupId>
-
<artifactId>jcl-over-slf4j</artifactId>
-
<version>1.7.9</version>
-
</dependency>
-
<dependency>
-
<groupId>org.mybatis</groupId>
-
<artifactId>mybatis</artifactId>
-
<version>3.2.8</version>
-
</dependency>
-
<dependency>
-
<groupId>org.mybatis</groupId>
-
<artifactId>mybatis-spring</artifactId>
-
<version>1.2.2</version>
-
</dependency>
-
</dependencies>
代码:
-
package com.vv.plugins;
-
-
import java.util.ArrayList;
-
import java.util.Collections;
-
import java.util.Iterator;
-
import java.util.List;
-
import java.util.Map;
-
import java.util.Properties;
-
import java.util.concurrent.ConcurrentHashMap;
-
import java.util.concurrent.atomic.AtomicLong;
-
-
import javax.management.MalformedObjectNameException;
-
-
import org.apache.commons.codec.digest.DigestUtils;
-
import org.apache.ibatis.executor.Executor;
-
import org.apache.ibatis.mapping.MappedStatement;
-
import org.apache.ibatis.plugin.Interceptor;
-
import org.apache.ibatis.plugin.Intercepts;
-
import org.apache.ibatis.plugin.Invocation;
-
import org.apache.ibatis.plugin.Plugin;
-
import org.apache.ibatis.plugin.Signature;
-
import org.apache.ibatis.session.ResultHandler;
-
import org.apache.ibatis.session.RowBounds;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.softee.management.annotation.MBean;
-
import org.softee.management.annotation.ManagedAttribute;
-
import org.softee.management.exception.ManagementException;
-
import org.softee.management.helper.MBeanRegistration;
-
-
@Intercepts({
-
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
-
RowBounds.class, ResultHandler.class }),
-
@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
-
public class MapperInterceptor implements Interceptor {
-
public static Logger LOG = LoggerFactory.getLogger(MapperInterceptor.class);
-
-
private Properties properties;
-
-
private static Map MAP = new ConcurrentHashMap(400);
-
-
static {
-
Runnable r = new Runnable() {
-
-
@Override
-
public void run() {
-
while (true) {
-
Map oldMap = MAP;
-
MAP = new ConcurrentHashMap(400);
-
List list = new ArrayList(oldMap.values());
-
Collections.sort(list);
-
Iterator it = list.iterator();
-
while (it.hasNext()) {
-
SqlInfo sql = it.next();
-
long avgts = (sql.getTotalts().get() / sql.getTotalcount().get());
-
long avgrows = (sql.getTotalrows().get() / sql.getTotalcount().get());
-
LOG.info("接口 :" + sql.getMapper() + ",SQL_ID:" + sql.getMd5() + ",一共执行" + sql.getTotalcount()
-
+ "次,平均时间" + avgts + "毫秒," + "平均返回记录数" + avgrows);
-
-
}
-
try {
-
Thread.sleep(MonitorParameter.getInstance().getMonitorInterval() * 1000);
-
} catch (InterruptedException e) {
-
-
e.printStackTrace();
-
}
-
}
-
}
-
};
-
new Thread(r).start();
-
}
-
-
@Override
-
public Object intercept(Invocation invocation) throws Throwable {
-
long start = System.currentTimeMillis();
-
List returnValue = (List) invocation.proceed();
-
long end = System.currentTimeMillis();
-
-
Object[] args = invocation.getArgs();
-
MappedStatement ms = (MappedStatement) args[0];
-
Object p = args[1];
-
RowBounds bounds = (RowBounds) args[2];
-
String boundSql = ms.getBoundSql(p).getSql();
-
-
SqlInfo info = MAP.get(boundSql);
-
if (info == null) {
-
info = new SqlInfo(ms, p);
-
MAP.put(boundSql, info);
-
}
-
info.logSqlInfo(p, returnValue.size(), end - start);
-
-
return returnValue;
-
}
-
-
@Override
-
public Object plugin(Object target) {
-
return Plugin.wrap(target, this);
-
}
-
-
@Override
-
public void setProperties(Properties properties0) {
-
this.properties = properties0;
-
}
-
}
-
-
@MBean(objectName = "jsmx:type=MonitorParameter")
-
class MonitorParameter {
-
private int maxts = 300;
-
private int maxrows = 100;
-
private int monitorInterval = 30;
-
-
@ManagedAttribute
-
public int getMaxts() {
-
return maxts;
-
}
-
-
@ManagedAttribute
-
public void setMaxts(int maxts) {
-
this.maxts = maxts;
-
}
-
-
@ManagedAttribute
-
public int getMaxrows() {
-
return maxrows;
-
}
-
-
@ManagedAttribute
-
public void setMaxrows(int maxrows) {
-
this.maxrows = maxrows;
-
}
-
-
@ManagedAttribute
-
public int getMonitorInterval() {
-
return monitorInterval;
-
}
-
-
@ManagedAttribute
-
public void setMonitorInterval(int monitorInterval) {
-
this.monitorInterval = monitorInterval;
-
}
-
-
private static class SingletonHandler {
-
private static MonitorParameter obj;
-
-
static {
-
obj = new MonitorParameter();
-
try {
-
new MBeanRegistration(obj).register();
-
} catch (MalformedObjectNameException e) {
-
-
e.printStackTrace();
-
} catch (ManagementException e) {
-
-
e.printStackTrace();
-
}
-
}
-
}
-
-
public static MonitorParameter getInstance() {
-
return SingletonHandler.obj;
-
}
-
}
-
-
class SqlInfo implements Comparable {
-
public static Logger LOG = LoggerFactory.getLogger(SqlInfo.class);
-
-
private String mapper;
-
private String sql;
-
private String md5;
-
private AtomicLong totalts = new AtomicLong(0);
-
private AtomicLong totalcount = new AtomicLong(0);
-
private AtomicLong totalrows = new AtomicLong(0);
-
-
public void setMapper(String mapper) {
-
this.mapper = mapper;
-
}
-
-
public SqlInfo(MappedStatement mappedStatement, Object parameterObject) {
-
this.sql = mappedStatement.getBoundSql(parameterObject).getSql();
-
this.mapper = mappedStatement.getId();
-
this.md5 = DigestUtils.md5Hex(sql);
-
}
-
-
public void logSqlInfo(Object para, int rows, long ts) {
-
totalts.addAndGet(ts);
-
totalcount.getAndIncrement();
-
totalrows.addAndGet(rows);
-
-
if (ts > MonitorParameter.getInstance().getMaxts() || rows > MonitorParameter.getInstance().getMaxrows()) {
-
LOG.warn("接口:" + this.mapper);
-
LOG.warn("SQL_ID:" + this.md5);
-
LOG.warn("SQL:" + this.sql);
-
LOG.warn("参数:" + para);
-
LOG.warn("执行时间:" + ts);
-
LOG.warn("返回记录:" + rows);
-
}
-
}
-
-
public String getSql() {
-
return sql;
-
}
-
-
public String getMd5() {
-
return md5;
-
}
-
-
public AtomicLong getTotalts() {
-
return totalts;
-
}
-
-
public AtomicLong getTotalcount() {
-
return totalcount;
-
}
-
-
public AtomicLong getTotalrows() {
-
return totalrows;
-
}
-
-
public String getMapper() {
-
return mapper;
-
}
-
-
@Override
-
public int compareTo(SqlInfo o) {
-
Long ts = this.getTotalcount().get();
-
Long ots = o.getTotalcount().get();
-
return ts.compareTo(ots);
-
}
-
-
}
使用:
将插件加入Spring管理,并作为插件添加到MyBatis

默认情况下,每30S打印SQL的统计信息,比如
17:56:29.023 [Thread-1] INFO com.vv.plugins.MapperInterceptor - 接口 :com.vv.songod.mapper.SodMapper.getAllUser,SQL_ID:9f683436fe68935af28708d8f2920792,一共执行1次,平均时间35毫秒,平均返回记录数513
17:56:29.023 [Thread-1] INFO com.vv.plugins.MapperInterceptor - 接口 :com.vv.songod.mapper.SodMapper.getUserByName,SQL_ID:e65912a2d6863ac310e66cbf3459ff46,一共执行2次,平均时间134毫秒,平均返回记录数1
默认如果有超过300ms执行时间或者返回行数超过100行的SQL,则直接打印在日志中.

另外程序添加了JMX支持,可以直接修改阈值而不需要重启程序.

超过 maxrows的返回行数,直接在日志打印
超过 maxts的执行时间,直接在日志打印
monitorInterval表示 每个多少S打印一次统计信息.
如果需要打印所有SQL的详细信息,则可以把maxts直接设置为0
itpub把泛型替换了,文件下载:
MapperInterceptor.txt
参考:
http://www.cnblogs.com/fangjian0423/p/mybatis-interceptor.html
http://www.cnblogs.com/babyhhcsy/p/4500884.html
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29254281/viewspace-1976044/
,如需转载,请注明出处,否则将追究法律责任。