mybatis 拦截器
  TEZNKK3IfmPf 2023年11月12日 16 0

1、前言
最近使用了mybatis的sql语句动态注入,可以使用@Component的方式进行自动扫描,也可以使用
拦截器技术对已有的sql语句进行拦截。不过拦截器只能拦截已有的sql语句,如果在拦截之前没有sql
语句,将会出现空指针异常,应该是mybatis内部在进行调用的时候出现的空指针,如果说非要在拦截
器里面直接构造sql语句,就必须得找到何处出现了空指针异常,并在其前面对执行语句进行拦截并
构造。

2、入门
Mybatis提供了Interceptor接口,我们只需要实现这个接口里面的相关函数就行了,一个标准的拦截器
应该包含以下几部分:

@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}))
@Component
public abstract class AbstructInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable{

return invocation.proceed();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {

}

}

其中,intercept 方法里面需要实现我们获取原始sql/params,然后对sql进行构造重组并且重新
放入到被拦截待执行的sql中。

先来说说相关的 annolation吧,@Intercepts 注释代表这是一个拦截器,里面可以放入多个待拦截
对象,它们之间以空格隔开。@Signature 注释里面有三个参数,分别是
type:表示拦截的接口,可以拦截的接口一共有四个,比较常见的是Executor.class 和 StatementHandler.class
接口。读了源代码就会发现,实际上 StatementHandler.class 是 Executor.class 的一个子过程。
method:拦截对应接口的相关方法,例如,当拦截Executor.class的时候,就可以去查看其实现的方法,
比较常见的方法有 query和 update 两种。
args:是对应方法实现的参数,比如Executor.class 里面的query 有两种实现方法,分别有两种不同的
形参列表,那么我们在这里进行拦截的时候也可以写两种不同的参数列表,代表了拦截两种不同的query方法。
看了源代码可以发现,实际上,少形参的query在内部调用了多形参的query方法,所以实际上没必要拦截多
形参的方法,否则在少形参里面会被拦截两次,从而产生意料之外的问题

@Component 代表该拦截器是一个bean,在spring boot项目扫描的时候会自动注入到项目中

解决的问题:为了避免mybatis因增加或者减少一两个字段从而需要去修改.xml文件的繁琐性,用拦截器进行动态
生成的通用sql只需要找到那个column,便会自动注入并进行判断,减少了人工维护庞大的.xml mybatis的sql文件
的复杂性。主要用在生成where语句,插入语句的value,更新语句的set等方面

技巧1:实现一个抽象类来实现 Interceptor接口,然后其他子类继承该抽象类即可

// AbstructInterceptor.java
public abstract class AbstructInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable{
invocation(invocation);
return invocation.proceed();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {

}

protected abstract void invocation(Invocation invocation);
}
//QueryInterceptor.java
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}))
@Component
public class QueryInterceptor extends AbstructInterceptor {
@Override
protected void invocation(Invocation invocation) {

}
}

技巧2:将实现类xxxInterceptor的实现body抽象出来放在实体文件夹中,在xxxInterceptor直接
进行引入即可,该方法使用了单一职责原则,减少了维护的难度。

一般来说,因为拦截器拦截的对象是mybatis将要执行的全部 query ,所以我们只需要针对baseModel
来写拦截器,其子类可以使用递归的方式进行构造。(或又叫深度优先搜索)

具体怎么写,请观看以下类的详细的sdk

MappedStatement.class
MetaObject.class
Configuration.class
Invocation.class
StatementHandler.class
SqlNode.class

只有详细了解了如何使用这些class对sql进行操作,才能用起来得心应手,否则出现问题就得百度,事情将变得没有意思

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2023年11月15日   168   0   0 MyBatisxml
TEZNKK3IfmPf