MyBatis-Plugins
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的更多相关文章
- mybatis plugins实现项目【全局】读写分离
在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...
- mybatis源码配置文件解析之四:解析plugins标签
在前边的博客在分析了mybatis解析typeAliases标签,<mybatis源码配置文件解析之三:解析typeAliases标签>.下面来看解析plugins标签的过程. 一.概述 ...
- springboot整合mybatis开发
1创建项目,在启动类上添加映射扫描注解 2导入依赖,添加mybatis generator自动生成代码插件 <!-- mybatis generator 自动生成代码插件 --> < ...
- 逆水行舟 —— MyBatis
第一轮总结性笔记 这是一个很漫长的过程,我买了套课程,将在日后记录学习笔记,取名为逆水行舟系列 MyBatis的基础 根据MyBatis的官方介绍: 整个测试项目结构如下:使用Maven架构项目 po ...
- mybatis generator自动生成sqlmap代码的不完善之处以及解决方法
a) 建表时,字段名称建议用"_"分隔多个单词,比如:AWB_NO.REC_ID...,这样生成的entity,属性名称就会变成漂亮的驼峰命名,即:awbNo.recId b)or ...
- MyBatis Generator实现MySQL分页插件
MyBatis Generator是一个非常方便的代码生成工具,它能够根据表结构生成CRUD代码,可以满足大部分需求.但是唯一让人不爽的是,生成的代码中的数据库查询没有分页功能.本文介绍如何让MyBa ...
- Mybatis三剑客介绍
1.MyBatis generator 利用mybatis-generator自动生成代码 下载地址: https://download.csdn.net/download/qq_36625806/ ...
- mybatis(mysql)代码生成器扩展
前些天在做我的KSF框架的时候需要用到mybatis代码生成器, 但是发现有一些东西需要调整,主要集中在以下几点: 1. 加入batchInsert 2. 加入batchUpdate 3. mysq ...
- Mybatis 插件使用及源码分析
Mybatis 插件 Mybatis插件主要是通过JDK动态代理实现的,插件可以针对接口中的方法进行代理增强,在Mybatis中比较重要的接口如下: Executor :sql执行器,包含多个实现类, ...
- Mybatis 懒加载使用及源码分析
Mybatis 懒加载的使用 什么是懒加载?懒加载的意思就是在使用的时候才去加载,不使用不去加载,相反的就叫饥饿加载或者立即加载.懒加载在Mybatis中一般是存在与联合查询的情况,比如查询一个对象的 ...
随机推荐
- mysql-tar包搭建过程
第一: wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz tar z ...
- Matplotlib学习---用mplot3d画莫比乌斯环(Mobius strip)
mplot3d是matplotlib里用于绘制3D图形的一个模块.关于mplot3d 绘图模块的介绍请见:https://blog.csdn.net/dahunihao/article/details ...
- bzoj 1015: [JSOI2008]星球大战starwar (逆向思维+并查集)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1015 思路: 题目是要我们对当前图拆掉k个点,问,每拆一个点后图中有多少个联通块,我们可以逆 ...
- 滚动ListView时图像顺序混乱
本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术.本文将为读者讲解滚动ListView时图像顺序混 ...
- 【CF618F】Double Knapsack(构造)
[CF618F]Double Knapsack(构造) 题面 洛谷 Codeforces 题解 很妙的一道题. 发现找两个数集很不爽,我们强制加强限制,我们来找两个区间,使得他们的区间和相等. 把区间 ...
- rt-thread 学习路线
@2019-01-25 [小记] > BSP制作与使用 将板载资源.芯片外设全部制作BSP,做到使用时只需在 menuconfig 中配置即用
- 【转】从Vue.js源码看异步更新DOM策略及nextTick
在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样: <template> <div> <div ref="test" ...
- [NOI2015]寿司晚宴(状压dp)
为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴.小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1,其中第种 ...
- Luogu P1648 看守
Luogu P1648 看守 题意简述 有n个d维的点,输出这些点两两之间曼哈顿距离中的最大值 数据范围 n<=1e6,d<=4 思路 暴力?时间复杂度O(\(n^2d\)) 考虑这样的一 ...
- Docker部署Jenkins测试环境
安装docker环境 yum install epel-release -y && yum install docker -y 如果是高手需要docker-compose的话就再装个d ...