MyBatis插件开发

Stella981
• 阅读 870

MyBatis插件开发

一、前言

MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。

MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。

默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

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

二、插件开发

编写插件实现Interceptor接口,并使用@Intercepts注解完成插件签名

MyBatis插件开发

在全局配置文件中注册插件

MyBatis插件开发

插件原理

按照插件注解声明,按照插件配置顺序调用插件plugin方法,生成被拦截对象的动态代理

多个插件依次生成目标对象的代理对象,层层包裹,先声明的先包裹;形成代理链

目标方法执行时依次从外到内执行插件的intercept方法。

MyBatis插件开发

多个插件情况下,我们往往需要在某个插件中分离出目标对象。可以借助MyBatis提供的SystemMetaObject类来进行获取最后一层的h以及target属性的值

Interceptor接口

Intercept:拦截目标方法执行

plugin:生成动态代理对象,可以使用MyBatis提供的Plugin类的wrap方法

setProperties:注入插件配置时设置的属性

MyBatis插件开发

常用代码:从代理链中分离真实被代理对象

//1、分离代理对象。由于会形成多次代理,所以需要通过一个while循环分离出最终被代理对象,从而方便提取信息
MetaObject metaObject = SystemMetaObject.forObject(target);
while(metaObject.hasGetter("h")) {
Object h = metaObject.getValue("h");
metaObject = SystemMetaObject.forObject(h);
}
//2、获取到代理对象中包含的被代理的真实对象
Object obj = metaObject.getValue("target");
//3、获取被代理对象的MetaObject方便进行信息提取
MetaObject forObject = SystemMetaObject.forObject(obj);

三、MyBatis实用场景

PageHelper插件进行分页

批量操作

存储过程

typeHandler处理枚举

PageHelper插件进行分页

PageHelper是MyBatis中非常方便的第三方分页插件。

官方文档:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README\_zh.md

我们可以对照官方文档的说明,快速的使用插件:

1、导入相关包pagehelper-x.x.x.jar和jsqlparser-0.9.5.jar。
2、在MyBatis全局配置文件中配置分页插件。

MyBatis插件开发

3、使用PageHelper提供的方法进行分页
4、可以使用更强大的PageInfo封装返回结果

批量操作

默认的openSession() 方法没有参数,它会创建有如下特性的:

①会开启一个事务(也就是不自动提交)
②连接对象会从由活动环境配置的数据源实例得到。
③事务隔离级别将会使用驱动或数据源的默认设置。
④预处理语句不会被复用,也不会批量处理更新。

openSession 方法的ExecutorType类型的参数,枚举类型:

①ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情(这是默认装配的)。它为每个语句的执行创建一个新的预处理语句。
②ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
③ExecutorType.BATCH: 这个执行器会批量执行所有更新语句

MyBatis插件开发

批量操作我们是使用MyBatis提供的BatchExecutor进行的,他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发给数据库一次。

publicvoidtest01() {
SqlSession openSession = build.openSession(ExecutorType.BATCH);
UserDao mapper = openSession.getMapper(UserDao.class);
longstart = System.currentTimeMillis();
for(inti = 0; i < 1000000; i++) {
String name = UUID.randomUUID().toString().substring(0, 5);
mapper.addUser(newUser(null, name, 13));
}
openSession.commit();
openSession.close();
longend = System.currentTimeMillis();
System.out.println("耗时时间:"+(end-start));
}

100万记录添加测试结果:消耗时间:75583

与Spring整合中,我们推荐,额外的配置一个可以专门用来执行批量操作的sqlSession

需要用到批量操作的时候,我们可以注入配置的这个批量SqlSession。通过他获取到mapper映射器进行操作。

MyBatis插件开发

注意:
1、批量操作是在session.commit()以后才发送sql语句给数据库进行执行的
2、如果我们想让其提前执行,以方便后续可能的查询操作获取数据,我们可以使用sqlSession.flushStatements()方法,让其直接冲刷到数据库进行执行。

存储过程

实际开发中,我们通常也会写一些存储过程,MyBatis也支持对存储过程的调用

一个最简单的存储过程
delimiter $$
create procedure test()
begin
select 'hello';
end $$
delimiter ;

存储过程的调用
1、select标签中statementType=“CALLABLE”
2、标签体中调用语法:{call procedure_name(#{param1_info},#{param2_info})}

存储过程-游标处理:MyBatis对存储过程的游标提供了一个JdbcType=CURSOR的支持,可以智能的把游标读取到的数据,映射到我们声明的结果集中

调用实例:

MyBatis插件开发

MyBatis插件开发

publicclassPageEmp {
private int start;
private int end;
private int count;
private List emps;









orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@localhost:1521:orcl
orcl.username=scott
orcl.password=123456

MyBatis插件开发

自定义TypeHandler处理枚举

我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略:

①实现TypeHandler接口或者继承BaseTypeHandler
②使用@MappedTypes定义处理的java类型,使用@MappedJdbcTypes定义jdbcType类型
③在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理,或者在全局配置TypeHandler要处理的javaType

测试实例:一个代表部门状态的枚举类

MyBatis插件开发

1、测试全局配置EnumOrdinalTypeHandler

MyBatis插件开发

MyBatis插件开发

2、测试全局配置EnumTypeHandler

MyBatis插件开发

MyBatis插件开发

3、测试参数位置设置自定义TypeHandler

MyBatis插件开发

MyBatis插件开发

自定义TypeHandler

MyBatis插件开发

MyBatis插件开发

如果,您对我的这篇博文有什么疑问,欢迎评论区留言,大家互相讨论学习。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博文感兴趣,可以关注我的后续博客,我是【AlbertRui】。

转载请注明出处和链接地址,欢迎转载,谢谢!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
MyBatis拦截器实现分页
MyBatis分页拦截器实现前言    拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比
Stella981 Stella981
3年前
Mybatis通过Interceptor来简单实现影子表进行动态sql读取和写入
首先进行Mybatis 拦截器介绍    拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比方,对于Executor,M
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Eclipse插件开发_学习_00_资源帖
一、官方资料 1.eclipseapi(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fhelp.eclipse.org%2Fmars%2Findex.jsp%3Ftopic%3D%252Forg.eclipse.platform.doc.isv%252Fguide%2