Mybatis 通过拦截器动态修改SQL
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相关推荐
- 老年人教程:MyBatis拦截器动态修改SQL(更新与插入)语句
注:本文编写与 2019年12月17日, 内容可能存在时效性问题. 数据库使用MySQL5.7 集成于SpringBoot 2.0.X , 引用国产的开源工具类Hutool 本教程建议显示大纲视图 配 ...
- mybatis使用拦截器显示sql,使用druid配置连接信息
mybatis使用拦截器显示sql,使用druid配置连接信息 mybatis sql Druid 1.显示出sql内容: 新建2个类: MybatisInterceptor :拦截sql,并获得输出 ...
- Mybatis Interceptor 拦截器原理 源码分析
Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最 ...
- 一步步教你mybatis分页,mybatis分页拦截器 使用,mybatis拦截器分页
mybatis 分页详解.mybatis分页查询,mybatis分页拦截器使用.struts2下mybatis分页 mybatis默认是支持分页的,内部通过创建可滚动的Result ...
- mybatis 自定义拦截器
拦截器注解 mybatis自定义拦截器实现步骤: 实现org.apache.ibatis.plugin.Interceptor接口. 添加拦截器注解org.apache.ibatis.plugin.I ...
- linux 软件集成工具箱,在PB中动态修改SQL语句
在PB中动态修改SQL语句 分享到: 江苏省南通电信局网管中心 黄莹 ---- PowerBuilder是图形界面的Client/Server应用程序开发环境,可以很容易开发出功能强大的应用程序,在当 ...
- 使用GSP动态修改SQL语句
最近发现一款功能非常强大的解析SQL语句的引擎,GSP(全称General SQL Parser).这是一款专业的SQL引擎,适用于市面上流行的各种数据库,同时他也支持了马哈鱼分析器对SQL的分析.这 ...
- 定义Mybatis拦截器动态切换postgre数据库schema
背景 随着业务的发展和合规要求,产品数据库将切换到Postgres.之前不同技术域,不同交付工程的数据分库管理的方式切换到PG数据库后将通过分schema管理. ORM继续使用Mybatis,为使用迁 ...
- 利用mybatis拦截器注解处理sql
首先@Intercepts注解 可以看这篇文章https://blog.csdn.net/weixin_43505211/article/details/128050083 建个类 实现 Interc ...
最新文章
- linux 编译链接过程,编译程序 一:linux程序编译过程(一)-编译和链接
- 通用 图片/文字 水印函数
- makefile例子(经典)
- 顶级Javaer,常用的 14 个类库
- 最小的linux服务器_学习以最小的努力构建GraphQL服务器
- 实战演练丨SCN太大引发ORA-600[2252]
- web安全这个行业的前景怎么样?
- Visual Studio 发布新版API智能提示
- 您有一份Microsoft Office 365技能宝典等待签收
- 粒子群算法(1)----粒子群算法简单介绍
- Layui Ajax请求时加上 load 加载效果
- Java的二级动态菜单实现
- 上海自考计算机基础实践,上海自考00019计算机应用基础实践考核考试大纲
- CDN的原理技术及使用方法
- RGB颜色中关于Alpha通道的计算
- 基于SONY CCD ICX285的成像电路设计
- rtx3080和rtx3080ti性能差距 rtx3080和rtx3080ti 参数对比哪个好
- usnews美国大学计算机排名2021,2021年USNEWS美国大学计算机
- 第五届“强网”拟态防御国际精英挑战赛——特邀战队篇
- springboot部署到centos访问不成功
热门文章
- swift项目嵌入flutter的module混合开发(官方推荐模式)
- H3C MSR3020路由NQA实例配置
- 有关VScode 配置MinGW32_9.2.0+OpenGL+GLFW+GLAD
- Linux(CentOS) 安装JDK
- instanceof java 报错_java中instanceof怎么理解?java中instanc 爱问知识人
- 我们是如何走到今天的?
- android obb分包,Unity 出OBB分包 和 安装
- github上很好的iOS资源集锦
- 联邦学习隐私保护相关知识总结
- jQuery轮播图(详细注释)