01 使用场景

当我们在多租户的项目中,编写SQL语句都要带上tenant字段,用于区分不同的租户只能操作自己的数据。

比如,像下面的SQL

select * from member where id = #{id} and tenant = #{tenant}

但是,我们的tenant属性一般是放在一个ThreadLocal的变量中的,便于我们随时获取该属性进行一些业务处理。

public class TenantContext {private static final ThreadLocal<String> TENANT_CONTEXT = new ThreadLocal<>();private TenantContext() {}public static void set(String tenant) {TENANT_CONTEXT.set(tenant);}public static String get() {return TENANT_CONTEXT.get();}public static void remove() {TENANT_CONTEXT.remove();}
}

这时,我们就可以在SQL中编写一些特殊字符串,然后用TenantContext.get()进行替换

-- 原始SQL
select * from member where id = #{id} and tenant = @tenant@
-- 替换后SQL
select * from member where id = #{id} and tenant = 'xxx'

这样就不用每个方法都要传tenant字段,然后替换#{tenant}了。

02 代码实现

首先,我们要编写一个mybatis的拦截器

import com.eddie.context.TenantContext;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.regex.Pattern;/*** 动态修改 mybatis 的 SQL** @author eddie*/
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
public class MybatisSqlInterceptor implements Interceptor {private static final Pattern TENANT_PATTERN = Pattern.compile("@tenant@");@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String sql = boundSql.getSql();sql = TENANT_PATTERN.matcher(sql).replaceAll("'" + TenantContext.get() + "'");Field sqlField = boundSql.getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(boundSql, sql);return invocation.proceed();}
}

然后,将这个拦截器放到spring容器中

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisSqlInterceptor mybatisSqlInterceptor() {return new MybatisSqlInterceptor();}
}

最后,编写我们的SQL语句,做测试即可

<select id="getById" resultType="com.eddie.bean.Member">select * from member where id = #{id} and tenant = @tenant@
</select>

03 测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MybatisPlusApplication.class)
public class MemberTest {@Resourceprivate MemberMapper memberMapper;@Beforepublic void before() {TenantContext.set("t1");}@Testpublic void test_getById() {Member member = memberMapper.getById(1);System.out.println(JSON.toJSONString(member));}
}

测试结果

Mybatis 通过拦截器动态修改SQL相关推荐

  1. 老年人教程:MyBatis拦截器动态修改SQL(更新与插入)语句

    注:本文编写与 2019年12月17日, 内容可能存在时效性问题. 数据库使用MySQL5.7 集成于SpringBoot 2.0.X , 引用国产的开源工具类Hutool 本教程建议显示大纲视图 配 ...

  2. mybatis使用拦截器显示sql,使用druid配置连接信息

    mybatis使用拦截器显示sql,使用druid配置连接信息 mybatis sql Druid 1.显示出sql内容: 新建2个类: MybatisInterceptor :拦截sql,并获得输出 ...

  3. Mybatis Interceptor 拦截器原理 源码分析

    Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最 ...

  4. 一步步教你mybatis分页,mybatis分页拦截器 使用,mybatis拦截器分页

              mybatis 分页详解.mybatis分页查询,mybatis分页拦截器使用.struts2下mybatis分页 mybatis默认是支持分页的,内部通过创建可滚动的Result ...

  5. mybatis 自定义拦截器

    拦截器注解 mybatis自定义拦截器实现步骤: 实现org.apache.ibatis.plugin.Interceptor接口. 添加拦截器注解org.apache.ibatis.plugin.I ...

  6. linux 软件集成工具箱,在PB中动态修改SQL语句

    在PB中动态修改SQL语句 分享到: 江苏省南通电信局网管中心 黄莹 ---- PowerBuilder是图形界面的Client/Server应用程序开发环境,可以很容易开发出功能强大的应用程序,在当 ...

  7. 使用GSP动态修改SQL语句

    最近发现一款功能非常强大的解析SQL语句的引擎,GSP(全称General SQL Parser).这是一款专业的SQL引擎,适用于市面上流行的各种数据库,同时他也支持了马哈鱼分析器对SQL的分析.这 ...

  8. 定义Mybatis拦截器动态切换postgre数据库schema

    背景 随着业务的发展和合规要求,产品数据库将切换到Postgres.之前不同技术域,不同交付工程的数据分库管理的方式切换到PG数据库后将通过分schema管理. ORM继续使用Mybatis,为使用迁 ...

  9. 利用mybatis拦截器注解处理sql

    首先@Intercepts注解 可以看这篇文章https://blog.csdn.net/weixin_43505211/article/details/128050083 建个类 实现 Interc ...

最新文章

  1. linux 编译链接过程,编译程序 一:linux程序编译过程(一)-编译和链接
  2. 通用 图片/文字 水印函数
  3. makefile例子(经典)
  4. 顶级Javaer,常用的 14 个类库
  5. 最小的linux服务器_学习以最小的努力构建GraphQL服务器
  6. 实战演练丨SCN太大引发ORA-600[2252]
  7. web安全这个行业的前景怎么样?
  8. Visual Studio 发布新版API智能提示
  9. 您有一份Microsoft Office 365技能宝典等待签收
  10. 粒子群算法(1)----粒子群算法简单介绍
  11. Layui Ajax请求时加上 load 加载效果
  12. Java的二级动态菜单实现
  13. 上海自考计算机基础实践,上海自考00019计算机应用基础实践考核考试大纲
  14. CDN的原理技术及使用方法
  15. RGB颜色中关于Alpha通道的计算
  16. 基于SONY CCD ICX285的成像电路设计
  17. rtx3080和rtx3080ti性能差距 rtx3080和rtx3080ti 参数对比哪个好
  18. usnews美国大学计算机排名2021,2021年USNEWS美国大学计算机
  19. 第五届“强网”拟态防御国际精英挑战赛——特邀战队篇
  20. springboot部署到centos访问不成功

热门文章

  1. swift项目嵌入flutter的module混合开发(官方推荐模式)
  2. H3C MSR3020路由NQA实例配置
  3. 有关VScode 配置MinGW32_9.2.0+OpenGL+GLFW+GLAD
  4. Linux(CentOS) 安装JDK
  5. instanceof java 报错_java中instanceof怎么理解?java中instanc 爱问知识人
  6. 我们是如何走到今天的?
  7. android obb分包,Unity 出OBB分包 和 安装
  8. github上很好的iOS资源集锦
  9. 联邦学习隐私保护相关知识总结
  10. jQuery轮播图(详细注释)