对于mybatis的拦截器这个想法我来自于三个地方

也就是下面这个三个地方是可以使用的,其他的情况需要开发人员根据实际情况来使用。

1、对于分页的查询,我们可以对于分页的方法采用比较规范的命名,然后根据这个命名来拦截需要分页查询的sql然后把分页的总数,分页数,页码数,页码总数等放在一个对象中返回去,这样分页只要调用dao的一个方法即可。

2、读写分离,我们可以在sql执行之前,获取sql是不是查询方法,然后根据这个条件去控制需要访问的数据源。

3、需要统计分析sql的执行时间(这边要说的是这里的执行包含了网络带宽,因为不是在mysql执行前后做的拦截,所以这里的sql并不只是sql在数据库真正执行的时间,要比实际长)

如何实现这样一个拦截器

首先mybatis官方早就想到我们开发会有这样的需求,所以开放了一个org.apache.ibatis.plugin.Interceptor这样一个接口。

我们只要实现这个接口并且加上注解然后重写intercept方法。

最后如果你使用的是mybatis.xml也就是mybatis本身单独的配置,你可以需要在这里配置相应的拦截器名字等。

如果你使用的是spring管理的mybatis,那么你需要在spring配置文件里面配置注册相应的拦截器。

代码实现

下面对于3,也就是实现统计sql执行时间,简单摘录一下实现代码。

还有两种开发可以根据自己的想法去实现和摸索。

package com.ssm;

import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties; import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
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.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.apache.log4j.Logger; @Intercepts({
@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 }) })
public class SqlStatementInterceptor implements Interceptor{ private static Logger logger = Logger.getLogger(SqlStatementInterceptor.class); @SuppressWarnings("unused")
private Properties properties; @Override
public Object intercept(Invocation arg0) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) arg0.getArgs()[0];
Object parameter = null;
if (arg0.getArgs().length > 1) {
parameter = arg0.getArgs()[1];
}
String sqlId = mappedStatement.getId();
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
Configuration configuration = mappedStatement.getConfiguration(); Object returnValue = null;
long start = System.currentTimeMillis();
returnValue = arg0.proceed();
long end = System.currentTimeMillis();
long time = (end - start); if (time > 1) {
String sql = getSql(configuration, boundSql, sqlId, time);
logger.error(sql);
} return returnValue;
} public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId, long time) {
String sql = showSql(configuration, boundSql);
StringBuilder str = new StringBuilder(100);
str.append(sqlId);
str.append(":");
str.append(sql);
str.append(":");
str.append(time);
str.append("ms");
return str.toString();
} public static String showSql(Configuration configuration, BoundSql boundSql) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", getParameterValue(parameterObject)); } else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
}
}
}
}
return sql;
} private static String getParameterValue(Object obj) {
String value = null;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
} }
return value;
} @Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, this);
} @Override
public void setProperties(Properties arg0) {
this.properties = arg0;
} }

下面是spring中的配置,如果你是单独配置mybatis配置文件的话,你需要查询一下如何配置

<!-- 配置mybitasSqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="com/ssm/entity"></property>
<property name="mapperLocations" value="classpath*:com/ssm/dao/sqlxml/*.xml"></property> <property name="plugins">
<array>
<bean class="com.ssm.SqlStatementInterceptor">
<property name="properties">
<value>
property-key=property-value
</value>
</property>
</bean>
</array>
</property>
</bean>

会在log日志中输出最后执行的sql和sqlID和sql执行的时间。

参考资料:

分页实现(本人没有亲自实现,因为现实情况还没有这样特别需要这样的业务逻辑):

http://www.cnblogs.com/jethypc/p/5149183.html

执行时间统计实现(我修改了其中spring的配置,不知为何下面博主的配置并没有用):

http://blog.csdn.net/tq02h2a/article/details/50772652

读写分离实现(其中的第四种方案就是利用了拦截器):

http://www.jianshu.com/p/2222257f96d3

你所不知道的mybatis居然也有拦截器的更多相关文章

  1. [转帖]你所不知道的C和C++运行库

    [C-C++]你所不知道的C和C++运行库 https://blog.csdn.net/humanking7/article/details/85887884 原作者也是转的blog 最近一个物理机上 ...

  2. 你所不知道的setInterval

    在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...

  3. 你所不知道的setTimeout

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...

  4. 你真的会玩SQL吗?你所不知道的 数据聚合

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  5. 你所不知道的linq(二)

    上一篇说了from in select的本质,具体参见你所不知道的linq.本篇说下from...in... from... in... select 首先上一段代码,猜猜结果是什么? class P ...

  6. 你所不知道的SQL Server数据库启动过程,以及启动不起来的各种问题的分析及解决技巧

    目前SQL Server数据库作为微软一款优秀的RDBMS,其本身启动的时候是很少出问题的,我们在平时用的时候,很少关注起启动过程,或者很少了解其底层运行过程,大部分的过程只关注其内部的表.存储过程. ...

  7. 你所不知道的SQL Server数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  8. Android中Context详解 ---- 你所不知道的Context

    转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好,  ...

  9. 你所不知道的html5与html中的那些事第三篇

    文章简介: 关于html5相信大家早已经耳熟能详,但是他真正的意义在具体的开发中会有什么作用呢?相对于html,他又有怎样的新的定义与新理念在里面呢?为什么一些专家认为html5完全完成后,所有的工作 ...

随机推荐

  1. ntp升级

    1. 系统与软件版本 1.1 系统版本 CentOS6.5 x86_64 1.2 ntpd软件版本 ntp-4.2.8p9.tar.gz 1.3 下载地址 官方下载地址:http://support. ...

  2. iOS 解决文本(uitextfield/uitextView)在中间显示而不在顶部显示 问题

    在对应的控制器中设置下面属性 self.automaticallyAdjustsScrollViewInsets = NO; 这样就好了.

  3. NSLineBreakMode

    typedef enum {    UILineBreakModeWordWrap = 0,    UILineBreakModeCharacterWrap,    UILineBreakModeCl ...

  4. 进程管理利器supervisor

    supervisor安装 方法一 1:用管理员安装python-setuptools suse zypper in python-setuptools centos yum install pytho ...

  5. On the first day here

    记录一下到这里的第一天 简单的自我介绍一下: 姓名: 郑超杰 昵称: 蝴蝶 English Nickname:   developerbfl     技能: OC  H5  Swift         ...

  6. 苹果4S

    港版.4S.白.非翻新机.16G.联通3G移动2G电信2G 1000 美版.4S.白.翻新.16G.联通3G移动2G电信3G 980

  7. git 和 svn

    GIT和SVN之间的五个基本区别 如果你在读这篇文章,说明你跟大多数开发者一样对GIT感兴趣,如果你还没有机会来试一试GIT,我想现在你就要了解它了. GIT不仅仅是个版本控制系统,它也是个内容管理系 ...

  8. Hadoop安装教程

    单机.伪分布式:http://dblab.xmu.edu.cn/blog/install-hadoop/ 集群:http://dblab.xmu.edu.cn/blog/install-hadoop- ...

  9. java 邮件发送 apache commons-email

    package com.sun.mail;import org.apache.commons.mail.Email;import org.apache.commons.mail.EmailExcept ...

  10. 把嵌入在eclipse中的tomcat日志分离出来

    现象 不知道从哪个版本的tomcat开始,windows版本的tomcat不再包含{tomcat_home}\logs\catalina.out这个文件,eclipse中配置好tomcat服务器之后, ...