一 Mybatis拦截器介绍

Mybatis拦截器设计的初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。所以Mybatis拦截器的使用范围是非常广泛的。

Mybatis里面的核心对象还是比较多,如下:

Mybatis核心对象 解释
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合
ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatement MappedStatement维护了一条mapper.xml文件里面 select 、update、delete、insert节点的封装
SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql 表示动态生成的SQL语句以及相应的参数信息
Configuration MyBatis所有的配置信息都维持在Configuration对象之中

Mybatis拦截器并不是每个对象里面的方法都可以被拦截的。Mybatis拦截器只能拦截Executor、ParameterHandler、StatementHandler、ResultSetHandler四个对象里面的方法。

  • Executor

Mybatis中所有的Mapper语句的执行都是通过Executor进行的。Executor是Mybatis的核心接口。从其定义的接口方法我们可以看出,对应的增删改语句是通过Executor接口的update方法进行的,查询是通过query方法进行的。Executor里面常用拦截方法如下所示。

public interface Executor {.../*** 执行update/insert/delete*/int update(MappedStatement ms, Object parameter) throws SQLException;/*** 执行查询,先在缓存里面查找*/<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;/*** 执行查询*/<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;/*** 执行查询,查询结果放在Cursor里面*/<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;...}
  • ParameterHandler

ParameterHandler用来设置参数规则,当StatementHandler使用prepare()方法后,接下来就是使用它来设置参数。所以如果有对参数做自定义逻辑处理的时候,可以通过拦截ParameterHandler来实现。ParameterHandler里面可以拦截的方法解释如下:

public interface ParameterHandler {.../*** 设置参数规则的时候调用 -- PreparedStatement*/void setParameters(PreparedStatement ps) throws SQLException;...}
  • StatementHandler

StatementHandler负责处理Mybatis与JDBC之间Statement的交互。

public interface StatementHandler {.../*** 从连接中获取一个Statement*/Statement prepare(Connection connection, Integer transactionTimeout)throws SQLException;/*** 设置statement执行里所需的参数*/void parameterize(Statement statement)throws SQLException;/*** 批量*/void batch(Statement statement)throws SQLException;/*** 更新:update/insert/delete语句*/int update(Statement statement)throws SQLException;/*** 执行查询*/<E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException;<E> Cursor<E> queryCursor(Statement statement)throws SQLException;...}

一般只拦截StatementHandler里面的prepare方法。

在Mybatis里面RoutingStatementHandler是SimpleStatementHandler(对应Statement)、PreparedStatementHandler(对应PreparedStatement)、CallableStatementHandler(对应CallableStatement)的路由类,所有需要拦截StatementHandler里面的方法的时候,对RoutingStatementHandler做拦截处理就可以了,如下的写法可以过滤掉一些不必要的拦截类。

@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class})
})
public class TableShardInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {if (invocation.getTarget() instanceof RoutingStatementHandler) {// TODO: 做自己的逻辑}return invocation.proceed();}@Overridepublic Object plugin(Object target) {// 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数return (target instanceof RoutingStatementHandler) ? Plugin.wrap(target, this) : target;}@Overridepublic void setProperties(Properties properties) {}
}

关于Statement、PreparedStatement和CallableStatement的一些区别。以及Statement和PreparedStatement相比PreparedStatement的优势在哪里。强烈建议大家去百度下。

  • ResultSetHandler

ResultSetHandler用于对查询到的结果做处理。所以如果你有需求需要对返回结果做特殊处理的情况下可以去拦截ResultSetHandler的处理。ResultSetHandler里面常用拦截方法如下:

public interface ResultSetHandler {/*** 将Statement执行后产生的结果集(可能有多个结果集)映射为结果列表*/<E> List<E> handleResultSets(Statement stmt) throws SQLException;<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;/*** 处理存储过程执行后的输出参数*/void handleOutputParameters(CallableStatement cs) throws SQLException;}

二 Mybatis拦截器的使用

Mybatis拦截器的使用,分两步:自定义拦截器类、注册拦截器类。

2.1 自定义拦截器类

自定义的拦截器需要实现Interceptor接口,并且需要在自定义拦截器类上添加@Intercepts注解。

2.1.1 Interceptor接口

Interceptor接口里面就三个方法。如下所示:

public interface Interceptor {/*** 代理对象每次调用的方法,就是要进行拦截的时候要执行的方法。在这个方法里面做我们自定义的逻辑处理*/Object intercept(Invocation invocation) throws Throwable;/*** plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理** 当返回的是代理的时候我们可以对其中的方法进行拦截来调用intercept方法 -- Plugin.wrap(target, this)* 当返回的是当前对象的时候 就不会调用intercept方法,相当于当前拦截器无效*/Object plugin(Object target);/*** 用于在Mybatis配置文件中指定一些属性的,注册当前拦截器的时候可以设置一些属性*/void setProperties(Properties properties);}

2.1.2 @Intercepts注解

Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法。@Intercepts注解定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {/*** 定义拦截点* 只有符合拦截点的条件才会进入到拦截器*/Signature[] value();
}

Signature来指定咱们需要拦截那个类对象的哪个方法。定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {/*** 定义拦截的类 Executor、ParameterHandler、StatementHandler、ResultSetHandler当中的一个*/Class<?> type();/*** 在定义拦截类的基础之上,在定义拦截的方法*/String method();/*** 在定义拦截方法的基础之上在定义拦截的方法对应的参数,* JAVA里面方法可能重载,不指定参数,不晓得是那个方法*/Class<?>[] args();
}

我们举一个例子来说明,比如我们自定义一个MybatisInterceptor类,来拦截Executor类里面的两个query。自定义拦截类MybatisInterceptor

@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 MybatisInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// TODO: 自定义拦截逻辑}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this); // 返回代理类}@Overridepublic void setProperties(Properties properties) {}
}

2.2 注册拦截器

注册拦截器就是去告诉Mybatis去使用我们的拦截器。注册拦截器类非常的简单,在@Configuration注解的类里面,@Bean我们自定义的拦截器类。比如我们需要注册自定义的MybatisInterceptor拦截器。

/*** mybatis配置*/
@Configuration
public class MybatisConfiguration {/*** 注册拦截器*/@Beanpublic MybatisInterceptor mybatisInterceptor() {MybatisInterceptor interceptor = new MybatisInterceptor();Properties properties = new Properties();// 可以调用properties.setProperty方法来给拦截器设置一些自定义参数interceptor.setProperties(properties);return interceptor;}}

三 Mybatis拦截器实例-自定义拦截器

上面讲了一大堆,最终的目的都是要使用上拦截器,接下来。我们通过几个简单的自定义拦截器来加深对Mybatis拦截器的理解。实例代码在链接地址:https://github.com/tuacy/microservice-framework 的 mybatis-interceptor module里面。

3.1 日志打印

自定义LogInterceptor拦截器,打印出我们每次sq执行对应sql语句。

3.2 分页

模仿pagehelper,咱们也来实现一个分页的拦截器PageInterceptor,该拦截器也支持自定义count查询。

3.3 分表

自定义拦截器TableShardInterceptor实现水平分表的功能。

3.4 对查询结果的某个字段加密

自定义拦截器EncryptResultFieldInterceptor对查询回来的结果中的某个字段进行加密处理。

上面拦截器的实现,在github https://github.com/tuacy/microservice-framework 的 mybatis-interceptor module里面都能找到具体的实现。


发现想把Mybatis拦截器的使用讲清楚还是比较难的,因为里面设计的到的东西太多了,用代码才是最好说话的,所以我在实例里面都尽可能的把注解写的很详细。希望能对大家有点帮助。

Mybatis拦截器相关推荐

  1. MySQL拦截器获取xml id_关于mybatis拦截器,有谁知道怎么对结果集进行拦截,将指定字段查询结果进行格式化...

    用MyBatis结果集拦截器做过这样一个需求: 由于项目需求经常变动,项目MySQL数据库都是存放JSON字符串,例如:用户的基本信息随着版本升级可能会有变动 数据表 CREATE TABLE `ac ...

  2. list mybatis 接收 类型_基于mybatis拦截器实现的一款简易影子表自动切换插件

    近期因工作需要,小编基于mybatis拦截器开发了一款简易影子表自动切换插件,可以根据配置实现动态修改表名,即将对原source table表的操作自动切换到对target table表的操作.该插件 ...

  3. 面试官:你能说说MyBatis拦截器原理吗?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Format cnblogs.com/fangjian042 ...

  4. 犯罪心理解读Mybatis拦截器

    原文链接:"犯罪心理"解读Mybatis拦截器 Mybatis拦截器执行过程解析 文章写过之后,我觉得 "Mybatis 拦截器案件"背后一定还隐藏着某种设计动 ...

  5. MyBatis拦截器原理探究MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis拦截 ...

  6. MyBatis拦截器有哪些以及分析

    MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允许你在已映射语句执行过程中 ...

  7. Mybatis拦截器 mysql load data local 内存流处理

    Mybatis 拦截器不做解释了,用过的基本都知道,这里用load data local主要是应对大批量数据的处理,提高性能,也支持事务回滚,且不影响其他的DML操作,当然这个操作不要涉及到当前所lo ...

  8. MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允 ...

  9. insert into select 主键自增_springboot2结合mybatis拦截器实现主键自动生成

    点击上方蓝字关注我们 1 01 前言 前阵子和朋友聊天,他说他们项目有个需求,要实现主键自动生成,不想每次新增的时候,都手动设置主键.于是我就问他,那你们数据库表设置主键自动递增不就得了.他的回答是他 ...

  10. Mybatis 拦截器介绍

    Mybatis 拦截器介绍 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 拦截器的一个作用就是我们 ...

最新文章

  1. linux下初步实现Keepalived+Nginx高可用
  2. python爬取网易云音乐_Python 从零开始爬虫(七)——实战:网易云音乐评论爬取(附加密算法)...
  3. Python裁剪图片,游戏大图裁小图
  4. Java中Properties类的操作配置文件
  5. Maven 插件介绍
  6. SCI论文降重技巧盘点 - 易智编译EaseEditing
  7. Nod32的内网升级方案
  8. java 代理模式详解
  9. JS实现页面保存为图片
  10. wgs84转cgcs2000 java_CGCS2000坐标系与WGS84的相互投影转换
  11. Snort IPS入侵防御系统模式
  12. c语言的area的用法,area的用法说明
  13. 第一站 Theano 简介
  14. 1《小学数学教材解读策略研究》课题研究方案
  15. 一种可能的投资策略和一种可能的模糊的快速股票估值方法
  16. 交互设计软件Framer X for mac软件测评
  17. 论目前最好的中文搜索引擎
  18. Docker-PS基本命令解析
  19. 教你怎么用Python,每天自动给女友免费发短信
  20. Python才是人工智能AI的首选编程语言,你值得拥有……

热门文章

  1. Ognl表达式基本原理和使用方法
  2. python cmd窗口 title_解决python在windows上运行弹出cmd窗口(dos窗口)
  3. 百度网盘提取码_百度网盘提取码查询终结版
  4. pdf用什么软件编辑最方便
  5. 7.过渡案例:①进度条 ②小米图标翻转(父盒子一定要加初始值!!!)
  6. 分析一块某宝上的WiFi摄像头模块
  7. php 按指定长度分割字符串,php实现将字符串按照指定距离进行分割的方法
  8. springboot跨域处理
  9. 微信清理僵尸粉脚本-基于auto.js
  10. 谷歌浏览器安装FeHelper插件