mybatis实战之解读 |
||||||||||||||||
+ 目录
mybatis实战之在服务的开发过程中,往往存在这样的需求,针对业务,实现对数据库操作语句做统一的处理。 比如对某些敏感数据如用户姓名、手机号等坐脱敏处理保存和查询、对未实现权限的查询通过添加关联查询实现权限控制查询结果等等。 这时,mybatis框架提供了的方式,允许在映射语句执行过程中的某一点进行拦截调用,进行自己的业务处理。
1、使用方法这里参考了官网的使用说明,只需实现 Interceptor 接口,并在类中指定想要拦截的方法签名即可。 比如:
?
然后在mybatis的配置文件中,添加插件的对应配置即可。
?
我们也可以在代码中添加,下面给出在spring中
?
分别加上处理的业务逻辑,这个就可以使用了。
2、需要注意的地方第一节简单介绍了,的使用方法,但在实际项目中这样还远远不够。 笔者在本节列举了一些需要注意的地方,供大家思考讨论。
的执行顺序的调用顺序分为两大种,第一种是拦截的不同对象,第二种是指拦截同一种对象的同一个方法。 第一种情况,例如拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象, 这两类的在整体执行的逻辑上是不同的。 StatementHandler 属于 Executor 执行过程中的一个子过程。 所以这两种不同类别的插件在配置时,一定是先执行 Executor 的,然后才会轮到 StatementHandler。 所以这种情况下配置的顺序就不重要了,在 MyBatis 逻辑上就已经控制了先后顺序。 第二种情况,例如都拦截 Executor 的 query 方法,这时你配置的顺序就会对这里有影响了。比如配置如下。
?
前面我们配置的顺序是1,2,3。在这里也会按照 1,2,3 的顺序被层层代理,代理后的结构如下:
?
然后到执行的逻辑:
顺序就是 3>2>1>Executor>1>2>3。MyBatis的采用责任链设计模式,多个之间的责任链是通过组织的。 我们一般都会在中的intercept方法中往往会有invocation.proceed()语句,其作用是将责任链向后传递,本质上便是的invoke。
与常用插件的整合遇到的问题pageHelper造成分页失效的问题 通过查看pagehelper源码,可以看到其inercept方法直接获取了excutor然后开始分页查询,当查询到结果时,便返回了。 就是pagehelper的intercept方法中没有invocation.proceed(),这意味着什么?
?
这意味着pagehelper没有继续向后传递责任链,而是自行处理直接返回。 由此,我们可以猜出该问题大概率与的执行顺序有关。 通过断点调试,验证了该猜想,当遇到分页查询时,执行到pagehelper就结束了,没有进入我们的自定义。这就可能造成我们自定义失效。 解决方案 因为PageHelper是Excetor类型的,所以我们如果想要在PageHelper前面执行,就必须要将我们自己的添加到他的后面。 这里只介绍最简单最优雅的一种方式: 注册一个ApplicationListener器, ContextRefreshedEvent 事件,当所有的bean都初始化完成后(即PageHelper也已经注册好了),再把我们的自定义 MyBatis 注册到 SqlSessionFactory 中。
可以提升的点Interceptor接口提供了三个方法分别是处理逻辑的主要方法、判断是否要进行拦截,然后做出决定是否生成一个代理的方法及设置参数的方法。
?
这里说的提升点,就是在实现接口的实现类中,我们可以在plugin方法里加上一个判断,因为默认情况下,根据顺序拦截后,就可以去处理对应逻辑了,这里加上一个判断拦截的条件,可以减少代理类的创建。
?
|