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中一般是存在与联合查询的情况,比如查询一个对象的 ...
随机推荐
- python 模块之-json
python 模块json import json x="[null,true,false,1]" print(json.loads(x)) #---------------- ...
- BZOJ3724PA2014Final Krolestwo——欧拉回路+构造
题目描述 你有一个无向连通图,边的总数为偶数.设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除).对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的 ...
- Python小练习
1.计算x的n次方 2.计算x的阶乘 3.计算1x1 + 2x2 + 3x3 ...+ NxN之和 def fun(n): s=0 while n > 0: s = s + n*n n = n ...
- HDU5977 Garden of Eden 【FMT】【树形DP】
题目大意:求有所有颜色的路径数. 题目分析:参考codeforces997C,先利用基的FMT的性质在$O(2^k)$做FMT,再利用只还原一位的特点在$O(2^k)$还原,不知道为什么网上都要点分治 ...
- UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】
题目分析: 首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法.我们把一个整体$f$拆成$f-,f\pm,f+$,然后另一个拆成$g-,g\pm,g+$.这样做的好处是能更清楚的分析问题. ...
- BZOJ4653 [NOI2016] 区间 【线段树】
题目分析: 首先思考一个二分答案的做法.我们可以注意到答案具有单调性,所以可以二分答案. 假设当前二分的答案是$ k $.那么按照大小顺序插入每个区间,同时在末端删除会对答案产生影响的区间.这里不妨用 ...
- Python可迭代对象中的添加和删除(add,append,pop,remove,insert)
list: classmates = ['Michael', 'Bob', 'Tracy'] classmates.append('Adam') //添加在末尾,没有add()方法 classmate ...
- 【XSY2190】Alice and Bob VI 树形DP 树剖
题目描述 Alice和Bob正在一棵树上玩游戏.这棵树有\(n\)个结点,编号由\(1\)到\(n\).他们一共玩\(q\)盘游戏. 在第\(i\)局游戏中,Alice从结点\(a_i\)出发,Bob ...
- Ionic生成的App安装在手机上后无法联网的解决方案
在Ionic中使用inappbrowser.themeablebrowser 组件打开网页,刚开始是好的,后来不知添加什么插件,导致了安装在手机上以后没有网络访问权限. 尝试了很多,最后才发现,此时, ...
- 【最短路算法】Dijkstra+heap和SPFA的区别
单源最短路问题(SSSP)常用的算法有Dijkstra,Bellman-Ford,这两个算法进行优化,就有了Dijkstra+heap.SPFA(Shortest Path Faster Algori ...