如何自定义MyBatis拦截器更改表名

 更新时间:2023年10月23日 14:08:05   作者:emanjusaka  
自定义MyBatis拦截器可以在方法执行前后插入自己的逻辑,这非常有利于扩展和定制 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>标签的使用

    这篇文章主要介绍了maven <repositories>标签和<pluginRepositories>标签的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • java正则匹配HTML中a标签里的中文字符示例

    java正则匹配HTML中a标签里的中文字符示例

    这篇文章主要介绍了java正则匹配HTML中a标签里的中文字符,涉及java中文正则及HTML元素操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2017-01-01
  • springboot mybatis手动事务的实现

    springboot mybatis手动事务的实现

    本文主要介绍了springboot mybatis手动事务的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12
  • springboot2.6.7集成springfox3.0.0的示例代码

    springboot2.6.7集成springfox3.0.0的示例代码

    这篇文章主要介绍了springboot2.6.7集成springfox3.0.0的示例代码,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-04-04
  • Java redis存Map对象类型数据的实现

    Java redis存Map对象类型数据的实现

    本文主要介绍了Java redis存Map<String,RedisCustom>对象类型数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • springboot自定义日志注解的实现

    springboot自定义日志注解的实现

    本文主要介绍了springboot自定义日志注解的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • JAVA技术实现上传下载文件到FTP服务器(完整)

    JAVA技术实现上传下载文件到FTP服务器(完整)

    这篇文章主要介绍了JAVA技术实现上传下载文件到FTP服务器(完整),本文使用 Apache Jakarta Commons Net(commons-net-3.3.jar) 基于FileZilla Server服务器实现FTP服务器上文件的上传/下载/删除等操作,需要的朋友可以参考下
    2015-07-07
  • java读取文件:char的ASCII码值=65279,显示是一个空字符的解决

    java读取文件:char的ASCII码值=65279,显示是一个空字符的解决

    这篇文章主要介绍了java读取文件:char的ASCII码值=65279,显示是一个空字符的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Java详解HashMap实现原理和源码分析

    Java详解HashMap实现原理和源码分析

    这篇文章主要介绍了Java关于HashMap的实现原理并进行源码分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Java后端中dto、vo、entity的区别浅析

    Java后端中dto、vo、entity的区别浅析

    这篇文章主要给大家介绍了关于Java后端中dto、vo、entity区别的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-01-01

最新评论