Spring Boot集成MyBatis-Plus:自定义拦截器实现动态表名切换

Spring Boot集成MyBatis-Plus:自定义拦截器实现动态表名切换


在这里插入图片描述

一、引言

介绍动态表名的场景需求,比如多租户系统、分表分库,或者不同业务模块共用一套代码但操作不同表。说明 MyBatis-Plus 默认绑定固定表名的问题。


二、项目配置

1. 集成 MyBatis-Plus

简单说明如何在 Spring Boot 中引入 MyBatis-Plus 并配置。

2. 依赖添加
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>最新版本号</version>
</dependency>

三、自定义拦截器实现动态表名

1. 拦截器原理

解释 MyBatis 拦截器的核心概念,介绍 Interceptor 接口和 @Signature 注解。

2. 拦截器实现代码

详细展示拦截器的完整实现:

@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DynamicTableInterceptor implements Interceptor {/*** 使用ThreadLocal来存储线程特有的数据,这里用于存储动态表名*/private static final ThreadLocal<String> TABLE_NAME_HOLDER = new ThreadLocal<>();/*** 设置动态表名** @param tableName 需要设置的表名,由调用者指定*                  此方法允许在运行时动态地设置数据库表名,以便在多数据源或动态表名的场景下灵活地切换表*/public static void setDynamicTableName(String tableName) {TABLE_NAME_HOLDER.set(tableName);}/*** 清除当前线程中的动态表名* 此方法用于清除ThreadLocal中存储的表名信息,以避免内存泄漏* 它应在每次使用动态表名后调用,确保不会对后续的请求产生影响*/public static void clearDynamicTableName() {TABLE_NAME_HOLDER.remove();}/*** 拦截器*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String tableName = TABLE_NAME_HOLDER.get();if (tableName != null) {/*** 从实体类的@tableName中获取表名,必须在实体类上面添加@tableName注解* 实体类中的@tableName注解中的值,必须是数据库中的表名,否则会报错* 例如 :@TableName("t_user_"),数据库是根据月份来的,在这里替换则需要根据当前月份进行拼接表名*/Class<?> entityType = boundSql.getParameterObject().getClass();String oldTableName = entityType.getAnnotation(TableName.class).value();String newSql = boundSql.getSql().replace(oldTableName, tableName);Field sqlField = boundSql.getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(boundSql, newSql);}return invocation.proceed();}
}
3. 使用拦截器动态设置表名
DynamicTableInterceptor.setDynamicTableName("your_dynamic_table_name");
try {myService.saveOrUpdateBatch(entities); // MyBatis-Plus 操作
} finally {DynamicTableInterceptor.clearDynamicTableName();
}

四、其他场景

MyBatis 拦截器(Interceptor)是 MyBatis 提供的强大扩展机制,可以拦截执行过程中的不同阶段并进行自定义操作。除了动态修改表名之外,拦截器还可以应用于以下多种场景:


1. SQL 日志记录与审计

  • 场景:记录每次执行的 SQL 语句、参数、执行时间等信息。
  • 用途:用于 SQL 审计、性能监控、问题排查。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();long startTime = System.currentTimeMillis();Object result = invocation.proceed();long endTime = System.currentTimeMillis();System.out.println("SQL: " + boundSql.getSql() + " Execution Time: " + (endTime - startTime) + "ms");return result;
}

2. 多租户数据隔离

  • 场景:根据当前租户信息自动添加过滤条件,确保数据隔离。
  • 用途:实现 SaaS 系统中不同租户的数据访问控制。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String originalSql = boundSql.getSql();String tenantId = TenantContext.getCurrentTenantId();String modifiedSql = originalSql + " WHERE tenant_id = " + tenantId;Field sqlField = boundSql.getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(boundSql, modifiedSql);return invocation.proceed();
}

3. SQL 参数加密与解密

  • 场景:对敏感数据(如身份证号、电话等)在 SQL 操作时进行自动加密或解密。
  • 用途:提高数据安全性,确保数据存储符合安全规范。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String sql = boundSql.getSql();// 自定义加密逻辑// 加密处理参数return invocation.proceed();
}

4. 自动分页处理

  • 场景:在执行查询时自动添加分页逻辑,避免手动分页处理。
  • 用途:简化分页查询的代码。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String originalSql = boundSql.getSql();String paginatedSql = originalSql + " LIMIT " + offset + ", " + limit;Field sqlField = boundSql.getClass().getDeclaredField("sql");sqlField.setAccessible(true);sqlField.set(boundSql, paginatedSql);return invocation.proceed();
}

5. 数据权限控制

  • 场景:根据用户角色或权限,自动添加数据过滤条件。
  • 用途:确保用户只能访问被授权的数据。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {StatementHandler handler = (StatementHandler) invocation.getTarget();BoundSql boundSql = handler.getBoundSql();String originalSql = boundSql.getSql();String userRole = SecurityContext.getCurrentUserRole();String restrictedSql = originalSql + " AND role = '" + userRole + "'";// 动态修改 SQLreturn invocation.proceed();
}

6. 缓存增强

  • 场景:自定义缓存逻辑,拦截查询请求,先检查缓存是否命中。
  • 用途:减少数据库访问次数,提高性能。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {// 检查缓存Object cachedResult = CacheManager.get(boundSql.getSql());if (cachedResult != null) {return cachedResult;}// 如果没有命中,执行查询Object result = invocation.proceed();// 存入缓存return result;
}

7. 动态数据源切换

  • 场景:根据不同的业务需求动态选择数据源。
  • 用途:实现读写分离或多数据库支持。

示例

@Override
public Object intercept(Invocation invocation) throws Throwable {String dataSourceKey = DataSourceContextHolder.getDataSourceKey();DynamicDataSource.setDataSourceKey(dataSourceKey);return invocation.proceed();
}

总结

MyBatis 拦截器为开发者提供了灵活的扩展能力,可以在 SQL 执行的多个阶段中注入自定义逻辑,从而实现多种高级功能。合理使用拦截器不仅能增强系统功能,还能提升性能和安全性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/478669.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(原创)Android Studio新老界面UI切换及老版本下载地址

前言 这两天下载了一个新版的Android Studio&#xff0c;发现整个界面都发生了很大改动&#xff1a; 新的界面的一些设置可参考一些博客&#xff1a; Android Studio新版UI常用设置 但是对于一些急着开发的小伙伴来说&#xff0c;没有时间去适应&#xff0c;那么怎么办呢&am…

数据新时代:如何选择现代数据治理平台(上)

谈现代数据治理系统的十大架构特征 最近一位老友找到我&#xff0c;咨询他的数据治理平台到底该不该换&#xff0c;背景是这样的&#xff1a;若干年前采购了一个市场主流的数据治理平台&#xff0c;功能大概就是数据治理三件套——标准、元数据和质量等经典数据治理的功能。现…

抖音SEO矩阵系统:开发技术分享

市场环境剖析 短视频SEO矩阵系统是一种策略&#xff0c;旨在通过不同平台上的多个账号建立联系&#xff0c;整合同一品牌下的各平台粉丝流量。该系统通过遵循每个平台的规则和内容要求&#xff0c;输出企业和品牌形象&#xff0c;以矩阵形式增强粉丝基础并提升商业价值。抖音作…

从零开始打造个人博客:我的网页设计之旅

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

STM32F103C8T6实时时钟RTC

目录 前言 一、RTC基本硬件结构 二、Unix时间戳 2.1 unix时间戳定义 2.2 时间戳与日历日期时间的转换 2.3 指针函数使用注意事项 ​三、RTC和BKP硬件结构 四、驱动代码解析 前言 STM32F103C8T6外部低速时钟LSE&#xff08;一般为32.768KHz&#xff09;用的引脚是PC14和PC…

Jmeter中的定时器

4&#xff09;定时器 1--固定定时器 功能特点 固定延迟&#xff1a;在每个请求之间添加固定的延迟时间。精确控制&#xff1a;可以精确控制请求的发送频率。简单易用&#xff1a;配置简单&#xff0c;易于理解和使用。 配置步骤 添加固定定时器 右键点击需要添加定时器的请求…

Fakelocation Server服务器/专业版 ubuntu

前言:需要Ubuntu系统 Fakelocation开源文件系统需求 Ubuntu | Fakelocation | 任务一 任务一 更新Ubuntu&#xff08;安装下载不再赘述&#xff09; sudo -i # 提权 sudo apt update # 更新软件包列表 sudo apt upgrade # 升级已安装的软…

5.5 W5500 TCP服务端与客户端

文章目录 1、TCP介绍2、W5500简介2.1 关键函数socketlistensendgetSn_RX_RSRrecv自动心跳包检测getSn_SR 1、TCP介绍 TCP 服务端&#xff1a; 创建套接字[socket]&#xff1a;服务器首先创建一个套接字&#xff0c;这是网络通信的端点。绑定套接字[bind]&#xff1a;服务器将…

超高流量多级缓存架构设计!

文章内容已经收录在《面试进阶之路》&#xff0c;从原理出发&#xff0c;直击面试难点&#xff0c;实现更高维度的降维打击&#xff01; 文章目录 电商-多级缓存架构设计多级缓存架构介绍多级缓存请求流程负载均衡算法的选择轮询负载均衡一致性哈希负载均衡算法选择 应用层 Ngi…

信创改造 - TongRDS 替换 Redis

记得开放 6379 端口哦 1&#xff09;首先在服务器上安装好 TongRDS 2&#xff09;替换 redis 的 host&#xff0c;post&#xff0c;passwd 3&#xff09;TongRDS 兼容 jedis # 例如&#xff1a;更改原先 redis 中对应的 host&#xff0c;post&#xff0c;passwd 改成 TongRDS…

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数

vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数 微信公众平台添加配置 微信公众平台 > 开发管理 > 开发设置 > 扫普通链接二维码打开小程序 配置链接规则需要下载校验文档给后端存入服务器中&#xff0c;保存配置的时候会校验一次&#xff0c;确定当前的配…

Git(一)基本使用

目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件&#xff0c;并使用 git init 在该目录下创建一个本地仓库&#xff0c; 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…

QML学习 —— 29、3种不同使用动画的方式(附源码)

效果 说明 第一种:属性动画 - 当启动软件时候自动执行动画。      第二种:行为动画 - 当属性发生变化则自动执行动画。      第三种:目标动画 - 将动画变为对象,指定对象的目标进行执行动画。 代码 import QtQuick 2.12 import QtQuick.Window 2.12 import QtQu…

下载并安装Visual Studio 2017过程

一、下载 1、下载链接 下载链接&#xff1a;官方网址 先登录 往下滑找到较早的下载 2、进行搜索下载 或者直接点击&#x1f517;网站跳转 3、确认系统信息进行下载 二、安装 下载完成后右键使用管理员身份运行 1、点击同意后安装 2、若报错—设置失败 打开控制面板-&g…

React(五)——useContecxt/Reducer/useCallback/useRef/React.memo/useMemo

文章目录 项目地址十六、useContecxt十七、useReducer十八、React.memo以及产生的问题18.1组件嵌套的渲染规律18.2 React.memo18.3 引出问题 十九、useCallback和useMemo19.1 useCallback对函数进行缓存19.2 useMemo19.2.1 基本的使用19.2.2 缓存属性数据 19.2.3 对于更新的理解…

vue实现列表滑动下拉加载数据

一、实现效果 二、实现思路 使用滚动事件监听器来检测用户是否滚动到底部&#xff0c;然后加载更多数据 监听滚动事件。检测用户是否滚动到底部。加载更多数据。 三、案例代码 <div class"drawer-content"><div ref"loadMoreTrigger" class&q…

Redis常见面试题总结(上)

Redis 基础 什么是 Redis&#xff1f; Redis &#xff08;REmote DIctionary Server&#xff09;是一个基于 C 语言开发的开源 NoSQL 数据库&#xff08;BSD 许可&#xff09;。与传统数据库不同的是&#xff0c;Redis 的数据是保存在内存中的&#xff08;内存数据库&#xf…

网络协议——BGP(边界网关协议)全网最详解

1. 什么是AS&#xff1f; AS: 指的是在同一个组织管理下&#xff0c;使用统一选路策略的设备集合&#xff0c;AS取值范围四字节&#xff08; 0~43亿&#xff09; 2. BGP概念 BGP是边界网关协议&#xff0c;用于自治系统间的动态协议路径矢量。基于TCP中应用层协议&#xff0c…

【JavaEE】Servlet:表白墙

文章目录 一、前端二、前置知识三、代码1、后端2、前端3、总结 四、存入数据库1、引入 mysql 的依赖&#xff0c;mysql 驱动包2、创建数据库数据表3、调整上述后端代码3.1 封装数据库操作&#xff0c;和数据库建立连接3.2 调整后端代码 一、前端 <!DOCTYPE html> <ht…

调用阿里通义千问大语言模型API-小白新手教程-python

阿里大语言模型通义千问API使用新手教程 最近需要用到大模型&#xff0c;了解到目前国产大模型中&#xff0c;阿里的通义千问有比较详细的SDK文档可进行二次开发,目前通义千问的API文档其实是可以进行精简然后学习的,也就是说&#xff0c;是可以通过简单的API调用在自己网页或者…