mybatis自定义拦截器sql执行语句修改-与分页插件结合使用

自定义拦截器修改sql

问题:系统需支持多租户使用,一个租户对应一个schema,增删改查的sql语句中需根据用户所属租户找到对应的schema,修改拼接sql,然后再执行sql语句
需实现效果:

执行前sqlselect * from student_test where id = 1
拦截修改后sqlselect * from s1.student_test where id = 1

实现代码:

@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class TestInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //通过MetaObject优雅访问对象的属性,这里是访问statementHandler的属性;:MetaObject是Mybatis提供的一个用于方便、
        //优雅访问对象属性的对象,通过它可以简化代码、不需要try/catch各种reflect异常,同时它支持对JavaBean、Collection、Map三种类型对象的操作。
        MetaObject metaObject = MetaObject.forObject(statementHandler,
                SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                new DefaultReflectorFactory());
        //先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        BoundSql boundSql = statementHandler.getBoundSql();
        Field sql = boundSql.getClass().getDeclaredField("sql");
        sql.setAccessible(true);
        //sql替换  根据sql中的表名与数据库表名匹配替换 test_table->s1.test_table
        // boundSql.getSql() ->获取待执行sql 
        String replace = replace(boundSql.getSql(), mappedStatement);
        //替换待执行sql
        sql.set(boundSql, replace);
        return invocation.proceed();
    }

注意点:

  1. 拦截器的拦截类需为StatementHandler, 如果拦截类为Executor,则修改数据操作修改类型的sql(update delete insert)不生效
  2. BoundSql中的sql为私有属性,需设置sql.setAccessible(true);

结合mybatis分页插件使用

问题:在分页查询中使用分页插件进行分页处理,在引入多租户多schema概念后,分页插件自动创建的分页查询无法查询出结果,控制台报stackoverflow错误
原因排查:debugger发现自定义拦截器存在sql查询,执行sql之后又再次进入sql分页拦截器,sql分页拦截器->自定义拦截器查询->分页拦截器
思路:取消sql查询,改为预先放入redis,再从redis中取出

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值