如何自定义MyBatis拦截器更改表名
自定义MyBatis拦截器可以在方法执行前后插入自己的逻辑,这非常有利于扩展和定制 MyBatis 的功能。本篇文章实现自定义一个拦截器去改变要插入或者查询的数据源。
@Intercepts
@Intercepts是Mybatis的一个注解,它的主要作用是标识一个类为拦截器。该注解通过一个@Signature注解(即拦截点),来指定拦截那个对象里面的某个方法。
具体来说,@Signature注解的属性type用于指定拦截器类型,可能的值包括:
- Executor(sql的内部执行器)
- ParameterHandler(拦截参数的处理)
- StatementHandler(拦截sql的构建)
- ResultSetHandler(拦截结果的处理)。
method属性表示在指定的拦截器类型中要拦截的方法
args属性表示拦截的方法对应的参数
实现步骤
实现org.apache.ibatis.plugin.Interceptor
接口,重写一下的方法:
添加拦截器注解,@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
配置文件中添加拦截器
注意需要在 Spring Boot 的 application.yml 文件中配置 mybatis 配置文件的路径。
mybatis拦截器目前不支持在application.yml配置文件中通过属性配置,目前只支持通过xml配置或者代码配置。
代码实现
Mybatis拦截器:
package top.emanjusaka.springboottest.mybatis.plugin; import org.apache.ibatis.executor.statement.StatementHandler; 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.Signature; import org.apache.ibatis.reflection.DefaultReflectorFactory; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import top.emanjusaka.springboottest.mybatis.annotation.DBTableStrategy; import java.lang.reflect.Field; import java.sql.Connection; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @Author emanjusaka * @Date 2023/10/18 17:25 * @Version 1.0 */ @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class DynamicMybatisPlugin implements Interceptor { private Pattern pattern = Pattern.compile("(from|into|update)[\\s]{1,}(\\w{1,})", Pattern.CASE_INSENSITIVE); @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); // 获取自定义注解判断是否进行分表操作 String id = mappedStatement.getId(); String className = id.substring(0, id.lastIndexOf(".")); Class<?> clazz = Class.forName(className); DBTableStrategy dbTableStrategy = clazz.getAnnotation(DBTableStrategy.class); if (null == dbTableStrategy || !dbTableStrategy.changeTable() || null == dbTableStrategy.tbIdx()) { return invocation.proceed(); } // 获取SQL BoundSql boundSql = statementHandler.getBoundSql(); String sql = boundSql.getSql(); // 替换SQL表名 Matcher matcher = pattern.matcher(sql); String tableName = null; if (matcher.find()) { tableName = matcher.group().trim(); } assert null != tableName; String replaceSql = matcher.replaceAll(tableName + "_" + dbTableStrategy.tbIdx()); // 通过反射修改SQL语句 Field field = boundSql.getClass().getDeclaredField("sql"); field.setAccessible(true); field.set(boundSql, replaceSql); field.setAccessible(false); return invocation.proceed(); } }
mapper的xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="top.emanjusaka.springboottest.score.repository.IScoreRepository"> <select id="selectAll" resultType="top.emanjusaka.springboottest.score.model.vo.ScoreVO"> select * from score </select> </mapper>
切换表名的注解:
package top.emanjusaka.springboottest.score.repository; import org.apache.ibatis.annotations.Mapper; import top.emanjusaka.springboottest.mybatis.annotation.DBTableStrategy; import top.emanjusaka.springboottest.score.model.vo.ScoreVO; import java.util.List; /** * @Author emanjusaka * @Date 2023/10/18 17:45 * @Version 1.0 */ @Mapper @DBTableStrategy(changeTable = true,tbIdx = "2") public interface IScoreRepository { List<ScoreVO> selectAll(); }
测试代码:
package top.emanjusaka.springboottest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import top.emanjusaka.springboottest.score.model.vo.ScoreVO; import top.emanjusaka.springboottest.score.service.IScore; import javax.annotation.Resource; import java.util.List; @SpringBootTest class SpringBootTestApplicationTests { @Resource private IScore score; @Test void contextLoads() { List<ScoreVO> list = score.selectAll(); list.forEach(System.out::println); } }
运行结果
通过上图可以看出,现在表名已经修改成了score_2
了。通过这种机制,我们可以应用到自动分表中。本文的表名的索引是通过注解参数传递的,实际应用中需要通过哈希散列计算。
到此这篇关于自定义MyBatis拦截器更改表名的文章就介绍到这了,更多相关MyBatis拦截器更改表名内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
maven <repositories>标签和<pluginRepositories>标签的使用
这篇文章主要介绍了maven <repositories>标签和<pluginRepositories>标签的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-07-07springboot2.6.7集成springfox3.0.0的示例代码
这篇文章主要介绍了springboot2.6.7集成springfox3.0.0的示例代码,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧2024-04-04java读取文件:char的ASCII码值=65279,显示是一个空字符的解决
这篇文章主要介绍了java读取文件:char的ASCII码值=65279,显示是一个空字符的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-08-08
最新评论