MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

除了用插件来修改 MyBatis 核心行为之外,还可以通过完全覆盖配置类来达到目的。只需继承后覆盖其中的每个方法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 方法即可。

一、可拦截的接口

1.Executor-执行器

public interface Executor {
// 不需要 ResultHandler
ResultHandler NO_RESULT_HANDLER = null;
// 更新
int update(MappedStatement ms, Object parameter) throws SQLException;
// 查询(先查缓存),带分页,BoundSql
<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;
// 查询游标
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
// 刷新(Statement)批处理语句
List<BatchResult> flushStatements() throws SQLException;
// 提交事务,参数为是否要强制
void commit(boolean required) throws SQLException;
// 回滚事务,参数为是否要强制
void rollback(boolean required) throws SQLException;
// 创建 CacheKey
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
// 判断是否缓存了,通过 CacheKey
boolean isCached(MappedStatement ms, CacheKey key);
// 清理 Session(本地一级) 缓存
void clearLocalCache();
// 延迟加载
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
// 获取事务
Transaction getTransaction();
// 关闭连接
void close(boolean forceRollback);
// 是否关闭
boolean isClosed();
// 设置 Executor
void setExecutorWrapper(Executor executor);
}

2.ParameterHandler-参数处理器

public interface ParameterHandler {
// 获取参数
Object getParameterObject();
// 设置参数
void setParameters(PreparedStatement ps) throws SQLException;
}

3.ResultSetHandler-结果集处理器

public interface ResultSetHandler {
// 将结果集转化成 List
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
// 将结果集转化成 Cursor
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
// 处理存储过程的 OUT(输出) 参数
void handleOutputParameters(CallableStatement cs) throws SQLException;
}

4.StatementHandler-SQL语句处理器

public interface StatementHandler {
// 准备语句
Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
// 参数处理
void parameterize(Statement statement) throws SQLException;
// 批量处理
void batch(Statement statement) throws SQLException;
// 更新处理
int update(Statement statement) throws SQLException;
// 查询处理,结果给 ResultHandler
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(Statement statement) throws SQLException;
// 获取绑定 SQL 语句
BoundSql getBoundSql();
// 获取参数处理器
ParameterHandler getParameterHandler();
}

二、自定义插件

实现 Interceptor 接口,并指定想要拦截的方法签名。最后在 xml 文件中配置全类名即可。

1.bean

@Alias("myUser")
public class MyUser implements Serializable {
private Integer id;
private String name;
private Integer age;

2.dao接口

public interface MyUserMapperAnnotation {
@Select("select * from myuser")
List<MyUser> selectMyUser(String a);
}

3.mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 注意 plugins 在配置文件中的位置
properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers? -->
<plugins>
<plugin interceptor="com.plugins.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins> <environments default="development-mysql">
<environment id="development-mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.8.136:3306/mybatis?allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments> <mappers>
<mapper class="com.dao.MyUserMapperAnnotation"/>
</mappers>
</configuration>

4.ExamplePlugin

/**
* @Intercepts 拦截器注解,包括一个或多个 @Signature
* @Signature 拦截的目标类信息,包括 type、method、args
* * type 要拦截的接口类型
* * method 接口中的方法名
* * args 方法的所有入参类型
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class ExamplePlugin implements Interceptor {
/**
* 拦截目标对象的目标方法的执行,将自定义逻辑写在该方法中
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("ExamplePlugin...intercept:" + invocation.getMethod()); // MetaObject 是 Mybatis 提供的一个用于访问对象属性的对象
MetaObject metaObject = SystemMetaObject.forObject(invocation); System.out.println("当前拦截到的对象:" + metaObject.getValue("target"));
System.out.println("SQL语句:" + metaObject.getValue("target.delegate.boundSql.sql"));
System.out.println("SQL语句入参:" + metaObject.getValue("target.delegate.parameterHandler.parameterObject"));
System.out.println("SQL语句类型:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.sqlCommandType"));
System.out.println("Mapper方法全路径名:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.id")); // 修改 SQL 语句
String newSQL = metaObject.getValue("target.delegate.boundSql.sql") + " limit 2";
metaObject.setValue("target.delegate.boundSql.sql", newSQL);
System.out.println("修改后SQL语句:" + newSQL); // 返回执行结果
return invocation.proceed();
} /**
* 为目标对象创建一个代理对象,使用 Plugin.wrap(target,this) 即可
* @param target 上次包装的代理对象
* @return 本次包装过的代理对象
*/
@Override
public Object plugin(Object target) {
System.out.println("ExamplePlugin...plugin:" + target);
return Plugin.wrap(target, this);
} /**
* 获取自定义配置参数
* @param properties
*/
@Override
public void setProperties(Properties properties) {
System.out.println("插件配置信息:" + properties);
System.out.println("someProperty:" + properties.get("someProperty"));
}
}

5.Main

public static void main(String[] args) throws IOException {
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); session = sqlSessionFactory.openSession();
MyUserMapperAnnotation mapper = session.getMapper(MyUserMapperAnnotation.class); System.out.println(mapper.selectMyUser("asdsad"));
} finally {
if (session != null) {
session.close();
}
}
}


http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins

MyBatis-Plugins的更多相关文章

  1. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  2. mybatis源码配置文件解析之四:解析plugins标签

    在前边的博客在分析了mybatis解析typeAliases标签,<mybatis源码配置文件解析之三:解析typeAliases标签>.下面来看解析plugins标签的过程. 一.概述 ...

  3. springboot整合mybatis开发

    1创建项目,在启动类上添加映射扫描注解 2导入依赖,添加mybatis generator自动生成代码插件 <!-- mybatis generator 自动生成代码插件 --> < ...

  4. 逆水行舟 —— MyBatis

    第一轮总结性笔记 这是一个很漫长的过程,我买了套课程,将在日后记录学习笔记,取名为逆水行舟系列 MyBatis的基础 根据MyBatis的官方介绍: 整个测试项目结构如下:使用Maven架构项目 po ...

  5. mybatis generator自动生成sqlmap代码的不完善之处以及解决方法

    a) 建表时,字段名称建议用"_"分隔多个单词,比如:AWB_NO.REC_ID...,这样生成的entity,属性名称就会变成漂亮的驼峰命名,即:awbNo.recId b)or ...

  6. MyBatis Generator实现MySQL分页插件

    MyBatis Generator是一个非常方便的代码生成工具,它能够根据表结构生成CRUD代码,可以满足大部分需求.但是唯一让人不爽的是,生成的代码中的数据库查询没有分页功能.本文介绍如何让MyBa ...

  7. Mybatis三剑客介绍

    1.MyBatis generator 利用mybatis-generator自动生成代码 下载地址:  https://download.csdn.net/download/qq_36625806/ ...

  8. mybatis(mysql)代码生成器扩展

    前些天在做我的KSF框架的时候需要用到mybatis代码生成器, 但是发现有一些东西需要调整,主要集中在以下几点: 1. 加入batchInsert  2. 加入batchUpdate 3. mysq ...

  9. Mybatis 插件使用及源码分析

    Mybatis 插件 Mybatis插件主要是通过JDK动态代理实现的,插件可以针对接口中的方法进行代理增强,在Mybatis中比较重要的接口如下: Executor :sql执行器,包含多个实现类, ...

  10. Mybatis 懒加载使用及源码分析

    Mybatis 懒加载的使用 什么是懒加载?懒加载的意思就是在使用的时候才去加载,不使用不去加载,相反的就叫饥饿加载或者立即加载.懒加载在Mybatis中一般是存在与联合查询的情况,比如查询一个对象的 ...

随机推荐

  1. BZOJ3224普通平衡树——旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  2. MySQL 同一台服务器同步数据

    声明:我配置出来的slave_io_running和slave_sql_running都是yes.但是数据并没有同步! 希望有遇到相同问题的朋友,能够告诉我一下解决方案? 首先,如何在同一个服务器安装 ...

  3. HDU4625 JZPTREE 【树形DP】【第二类斯特林数】

    题目大意: 对1到n求题目中描述的那个式子. 题目分析: 幂不好处理,转化为斯特林数. 根据$ n^k= \sum_ { i=0 }^k S(k,i)×i!×C(n,i) $. 我们可以将问题转化为对 ...

  4. codeforces553C Love Triangles

    题目链接:codeforces553C Love Triangles 我们来看一下对于一个合法三角形可能出现的边 我们发现,在确定了两边之后,第三条边是什么也就随之确定了 我们用\(1\)表示\(lo ...

  5. codeforces 1065F Up and Down the Tree

    题目链接:codeforces 1065F Up and Down the Tree 题意:给出一棵树的节点数\(n\)以及一次移动的最大距离\(k\),现在有一个标记在根节点1处,每一次可以进行一下 ...

  6. js中的arguments用法

    //arguments对象并不是一个数组,但是访问单个参数的方式与访问数组元素的方式相同 function show(){ console.log(arguments); //arguments.pu ...

  7. 「SDOI2014」数数 解题报告

    「SDOI2014」数数 题目描述 我们称一个正整数 \(N\) 是幸运数,当且仅当它的十进制表示中不包含数字串集合 \(S\) 中任意一个元素作为其子串. 例如当 \(S=(\)22, 333, 0 ...

  8. 【STM32】PWM DAC基本原理(实验:PWM实现DAC)

    虽然STM32F103ZET6具有内部DAC,但是也仅仅只有两条DAC通道,并且STM32还有其他的很多型号是没有DAC的.通常情况下,采用专用的D/A芯片来实现,但是这样就会带来成本的增加. 不过S ...

  9. centos7下mysql半同步复制原理安装测试详解

    原理简介: 在MySQL5.5之前,MySQL的复制其实都是异步复制(见下图),主库和从库的数据之间存在一定的延迟,这样存在一个隐患:当在主库上写入一个事务并提交成功,而从库尚未得到主库推送的BinL ...

  10. springboot 通过 hibernate 连接sqlserver 空间数据 位置数据

    示例代码:https://github.com/bigben0123/spring-boot-spatial-example 1,配置application.properties #sqlserver ...