您的位置:首页 > 数据库

Mybatis插件使用-统计sql执行时间

2017-09-07 15:22 489 查看
  背景介绍:最近由于产品数据量较大,sql执行十分低效,正在做数据库优化,所以想在日志中看到每个sql执行的时间,以方便针对性的优化。

  查找相关资料,了解到Mybatis有一款插件,是基于interceptor来实现的,可以在拦截器中来输出每个sql的执行时间,配置方便且简单,经过自测可用。

  1、在dao的配置文件中,在sqlSessionFactory配置项里添加插件依赖:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="mapperLocations" value="classpath:/sqlmap/*Mapper.xml" />
<property name="dataSource" ref="dataSource" />
<property name="plugins">
<array>
<!-- 基于拦截器的实现,配置拦截器所在工程的全路径 -->
<bean id="sqlStatementInterceptor" class="com.**.interceptor.SqlStatementInterceptor"/>
</array>
</property>
</bean>


  2、在工程com.**.interceptor包路径下添加SqlStatementInterceptor.java,具体代码如下:

/**
* Mybatis SQL拦截器,记录每个sqlId对应的执行时间
*
* @author yehaixiao
* @date 2017-09-07
*/
@Intercepts(value = {
@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }),
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }) })
public class SqlStatementInterceptor implements Interceptor {
private static Logger logger = Logger.getLogger(SqlStatementInterceptor.class);

@Override
public Object intercept(Invocation invocation) {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// sqlId为mapper文件中定义的id,例如:com.**.dao.**Mapper.selectByPrimaryKey
String sqlId = mappedStatement.getId();
// 开始时间
long start = System.currentTimeMillis();
try {
return invocation.proceed();
} catch (Exception e) {
logger.error(sqlId + "执行失败!", e);
return null;
} finally {
long end = System.currentTimeMillis();
long time = end - start;
StringBuilder str = new StringBuilder();
str.append(sqlId);
str.append(": ");
str.append("cost time ");
str.append(time);
str.append(" ms.");
String sqlInfo = str.toString();
logger.debug(sqlInfo);
}
}

@Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, this);
}

@Override
public void setProperties(Properties arg0) {

}
}


  说明:自定义的拦截器实现了org.apache.ibatis.plugin.Interceptor,Interceptor中有三个方法:

public abstract interface Interceptor {
public abstract Object intercept(Invocation paramInvocation) throws Throwable;

public abstract Object plugin(Object paramObject);

public abstract void setProperties(Properties paramProperties);
}


  我们主要实现了intercept方法,入参是一个Invocation,Invocation的内部结构如下所示:  

  

  

  第一个参数是长度为4的args数组,数组的第一个参数是一个MappedStatement,其实这个就是执行一个sql对应的对象,该对象中有个getId,获取到的结果就是mapper文件中sql定义的id,这样就很容易明白自定义的拦截器里intercept方法里第一句话含义。

  直到现在,相关的配置、代码以及说明全都结束,在执行sql的时候,日志中可以看到如下输出:  


  

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3933ff }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: