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中一般是存在与联合查询的情况,比如查询一个对象的 ...
随机推荐
- 可前端解密的加密方法探讨和str_replace和preg_replace分析
目的: 对字符串‘123456’进行后端加密,前端js可解密出真实字符 测试代码php: static $hashMap = array( '0' => '4', '1' => '9', ...
- 【Gym - 100796C 】Minimax Tree
BUPT2017 wintertraining(15) #7FMinimax Tree 题意 给你一棵多叉树,非叶子节点中分配k个为子节点的min函数,剩下的是max函数. 现在求根节点(1)的最大值 ...
- Linux 源码安装 Python3
下载源码包https://www.python.org/downloads/ 解压(以3.64版本为例)wget https://www.python.org/ftp/python/3.6.4/Pyt ...
- 【BZOJ2576】[JSOI2011]序的计数 (动态规划)
[BZOJ2576][JSOI2011]序的计数 (动态规划) 题面 BZOJ 题解 首先构建一个新的虚拟节点连接所有目标节点,强行将其作为第一个被访问的节点,这样子就解决了图不连通的问题. 除了目标 ...
- PHP函数memory_get_usage获取PHP内存清耗量
(PHP 4 >= 4.3.2, PHP 5, PHP 7) memory_get_usage — 返回分配给 PHP 的内存量 说明 int memory_get_usage ([ bool ...
- BZOJ 1143: [CTSC2008]祭祀river(最大独立集)
题面: https://www.lydsy.com/JudgeOnline/problem.php?id=1143 一句话题意:给一个DAG(有向无环图),求选出尽量多的点使这些点两两不可达,输出点个 ...
- Opennebula常用命令
查看虚拟机状态信息: [oneadmin@localhost /]$ onevm list 查看虚拟机配置: [oneadmin@localhost /]$ onevm show 25 启动虚拟机: ...
- Lambda 表达式有何用处?如何使用?
强烈推荐!!! 作者:Sevenvidia链接:https://www.zhihu.com/question/20125256/answer/324121308来源:知乎著作权归作者所有.商业转载 ...
- CF1101F Trucks and Cities
题意:给定线段上n个特殊点,m次询问. 每次询问:在第l个点到第r个点这一段区间中选出k个点,将其分成k + 1段.使得最长的段尽量短. 输出这m个询问中答案最大的. n<=400,m<= ...
- 洛谷P3354 河流
有点权边权的树,选出k个关键点,根必须选.每个点的贡献为点权 * 到最近的关键祖先的距离.求最小总贡献. 解:树形DP是最毒瘤的算法...... 设fxij表示以x为根的子树中选了j个关键点,且x的最 ...