mybatis 实现 SQL 查询拦截修改详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis 实现 SQL 查询拦截修改详解相关的知识,希望对你有一定的参考价值。

参考技术A 截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。

Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。比如我想针对所有的SQL执行某个固定的操作,针对SQL查询执行安全检查,或者记录相关SQL查询日志等等。

Mybatis为我们提供了一个Interceptor接口,可以实现自定义的拦截器。

intercept方法为具体的拦截对象的处理方法,传入的Invocation包含了拦截目标类的实力,拦截的方法和方法的入参数组。使用Invocation的procced执行原函数。

plugin 中执行判断是否要进行拦截进,如果不需要拦截,直接返回target,如果需要拦截则调用Plugin类中的wrap静态方法,如果当前拦截器实现了任意接口,则返回一个代理对象,否则直接返回(回忆代理模式的设计)。代理对象实际是一个Plugin类实例,它实现了InvocationHandler接口 ,InvocationHandler接口仅包含invoke方法用于回调方法。

当执行代理对象的接口方法时,会调用Plugin的invoke方法,它会把要执行的对象,方法和参数打包成Invocation对象传给拦截器的intercept方法。Invocation定义了一个procced方法,用于执行被拦截的原方法。

setProperties 方法顾名思义,用于设置属性的。bean的属性初始化方法有很多,这是其中的一种。

mybatis提供了@Intercepts注解用于声明当前类是拦截器,其值为@Signature数组,表明要拦截的接口、方法以及对应的参数类型

例如上面的类声明,第一个Signature标注拦截了StatementHandler类下的入参是一个Connection的名为prepare的方法。

第二个Signature标注拦截StatementHandler类中包含2个入参(分别为Statement和ResultHandler类型)的名为query的方法。

后面会分享更多运维方面的干货,感兴趣的朋友可以关注一下~

mybatis - 基于拦截器修改执行中的SQL语句

拦截器介绍

mybatis提供了@Intercepts注解允许开发者对mybatis的执行器Executor进行拦截。
Executor接口方法主要有update、query、commit、rollback等等。
主要思路为:

  1. 进入拦截器方法中
  2. 获取拦截器方法参数
  3. 获取解析参数及SQL
  4. 自定义生成自己的SQL语句
  5. 将自定义SQL设置进参数中
  6. 由mybatis处理后续问题

    拦截器代码

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;
@Component
@Intercepts({@org.apache.ibatis.plugin.Signature(type = Executor.class, method = "query",
        args = {
        MappedStatement.class,
                Object.class,
                RowBounds.class,
                ResultHandler.class,
                CacheKey.class,
                BoundSql.class})})
public class MybatisInterceptorConfig implements Interceptor {
     /*自定义SQL*/
     private String resetSql(String sql) {
         
     }
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        resetSql(invocation);
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }
    @Override
    public void setProperties(Properties properties) {
        
    }
    private void resetSql(Invocation invocation) {
        final Object[] args = invocation.getArgs();
        BoundSql boundSql = (BoundSql) args[5];
        if(StringUtils.isNotEmpty(boundSql.getSql())) {
            modify(boundSql,"sql",resetSql(boundSql.getSql()));
        }
    }
    private static void modify(Object object, String fieldName, Object newFieldValue){
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            if(!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.set(object, newFieldValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是关于mybatis 实现 SQL 查询拦截修改详解的主要内容,如果未能解决你的问题,请参考以下文章

自定义mybatis拦截器

spring boot Mybatis 拦截器,实现拼接sql和修改

Mybatis-Interceptor

mybatis - 基于拦截器修改执行中的SQL语句

Mybatis反射修改SQL值

Mybatis反射修改SQL值