背景介绍:最近由于产品数据量较大,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的时候,日志中可以看到如下输出:  

  


Mybatis插件使用-统计sql执行时间的更多相关文章

  1. Mybatis插件Plugin

    Mybatis开源Plugin中最熟知的pagehelper,重点made in China 很多人开始用pagehelper时候,肯定很纳闷,以mysql为例,明明没有加limit语句,为什么打印出 ...

  2. MyBatis7:MyBatis插件及示例----打印每条SQL语句及其执行时间

    Plugins 摘一段来自MyBatis官方文档的文字. MyBatis允许你在某一点拦截已映射语句执行的调用.默认情况下,MyBatis允许使用插件来拦截方法调用 Executor(update.q ...

  3. MyBatis 插件 : 打印 SQL 及其执行时间

    Plugins 摘一段来自MyBatis官方文档的文字. MyBatis允许你在某一点拦截已映射语句执行的调用.默认情况下,MyBatis允许使用插件来拦截方法调用: Executor(update. ...

  4. MyBatis插件及示例----打印每条SQL语句及其执行时间

    Plugins 摘一段来自MyBatis官方文档的文字. MyBatis允许你在某一点拦截已映射语句执行的调用.默认情况下,MyBatis允许使用插件来拦截方法调用 Executor(update.q ...

  5. Mybatis插件,能做的事情真的很多

    大家好,我是架构摆渡人.这是实践经验系列的第九篇文章,这个系列会给大家分享很多在实际工作中有用的经验,如果有收获,还请分享给更多的朋友. Mybatis是我们经常用的一款操作数据库的框架,它的插件机制 ...

  6. 统计sql语句执行效率

    --统计sql语句执行效率SELECT (total_elapsed_time / execution_count)/1000 N'平均时间ms' ,total_elapsed_time/1000 N ...

  7. Mybatis插件机制以及PageHelper插件的原理

    首先现在已经有很多Mybatis源码分析的文章,之所以重复造轮子,只是为了督促自己更好的理解源码. 1.先看一段PageHelper拦截器的配置,在mybatis的配置文件<configurat ...

  8. 动手实践Mybatis插件

    前言 Mybatis的插件开发过程的前提是必须要对Mybatis整个SQL执行过程十分熟悉,这样才能正确覆盖源码保证插件运行,总的来说Mybatis的插件式一种侵入式插件,使用时应该十分注意. 在之前 ...

  9. mybatis插件机制

    目录 mybatis插件机制 主要 类/接口 和 方法 mybatis插件机制实现 mybatis插件机制 mybatis的插件机制使用动态代理实现,不了解的朋友请先了解代理模式和动态代理:插件本质是 ...

随机推荐

  1. hdu 5055

    http://acm.hdu.edu.cn/showproblem.php?pid=5055 n个digit能组合出的最大无前导0奇数 无聊的模拟 #include <cstdio> #i ...

  2. centos下网口vlan设置

    如果要使vlan之间进行通信,我们通常会使用三层交换机或者路由器子接口模式来做.Linux上关于VLAN与Cisco交换机中继连接,也是可以实现其互相之间的通信的. 环境:RHEL 5.2 最小化安装 ...

  3. uniGUI for C++ builder之杂七杂八小知识

    uniGUI for C++ builder之杂七杂八小知识 2018年09月30日 22:16:05 中国银行之路在脚下 阅读数:41 标签: uniguibuilder 更多 个人分类: C++ ...

  4. iOS 应用如何完全支持 IPv6-ONLY 网络?

    iOS 应用如何完全支持 IPv6-ONLY 网络?¶ 警告 您当前查看的页面是未经授权的转载! 如果当前版本排版错误,请前往查看最新版本:http://www.cnblogs.com/qin-nz/ ...

  5. .NET MVC 学习笔记(五)— Data Validation

    .NET MVC 学习笔记(五)—— Data Validation 在实际应用中,我们需要对数据进行增查改删业务,在添加和修改过程中,无论你编写什么样的网页程序,都需要对用户的数据进行验证,以确数据 ...

  6. AreaHttpControllerSelector 对 Web Api 实现 Area 路由控制

    结合此文章:http://www.cnblogs.com/wuhuacong/p/5828038.html using System; using System.Collections.Concurr ...

  7. 【mock】后端不来过夜半,闲敲mock落灯花 (mockjs+Vuex+Vue实战)

      mock的由来[假]   赵师秀:南宋时期的一位前端工程师 诗词背景:在一个梅雨纷纷的夜晚,正处于项目编码阶段,书童却带来消息:写后端的李秀才在几个时辰前就赶往临安度假去了,!此时手头仅有一个简单 ...

  8. 配置iSCSI部署网络存储

    iSCSI( Internet Small Computer System Interface 互联网小型计算机系统接口)是由IBM 下属的两大研发机构一一加利福尼亚AImaden和以色列Haifa研 ...

  9. c++11中关于std::thread的join的思考

    c++中关于std::thread的join的思考 std::thread是c++11新引入的线程标准库,通过其可以方便的编写与平台无关的多线程程序,虽然对比针对平台来定制化多线程库会使性能达到最大, ...

  10. 从用户浏览器输入url到用户看到页面结果的过程,发生了什么事情?

    1.域名解析 域名解析的过程:  1).查询浏览器自身DNS缓存 2).若上面没有查找到,则搜索操作系统自身的dns缓存 3).若上面没有找到,则尝试读取hosts文件 4).若上面没有找到,向本地配 ...