• MyBatis-Plus动态表名插件使用


    一、MyBatis-Plus动态表名插件使用

    官方文档-动态表名插件:https://baomidou.com/pages/2a45ff/#dynamictablenameinnerinterceptor

    官方有demo,使用起来还是蛮简单的。

    1、DynamicTableNameInnerInterceptor插件源码

    DynamicTableNameInnerInterceptor:原理为解析替换设定表名为处理器的返回表名,表名建议可以定义复杂一些避免误替换。

    重点看 changeTable方法。

    • TableNameHandler tableNameHandler是一个接口。使用动态表名插件时,必须要有 TableNameHandler的实现类。

    在这里插入图片描述

    2、使用

    模拟使用场景:

    一个 entity 对应多张表(多张表结构一致,只有表名称不同),在使用时,可以动态映射表名称。
    比如:按照时间分表,某些业务冷热数据分离后数据存在不同的表中等。根据自定义的算法找到我们需要查询的表名。

    下面我通过参数的方式传入动态表名来操作。

    2.1 请求参数动态表名传递辅助类

    /**
     * 请求参数动态表名传递辅助类
     */
    public class RequestDynamicTableNameHelper {
    
    	/**
    	 * 请求参数存取(表名)。请求参数自定义,官方Demo定义为ThreadLocal>
    	 */
    	private static final ThreadLocal<String> REQUEST_DATA = new ThreadLocal<>();
    
    	/**
    	 * 设置请求参数
    	 *
    	 * @param requestData
    	 *            请求参数-表名
    	 */
    	public static void setRequestData(String requestData) {
    		REQUEST_DATA.set(requestData);
    	}
    
    	/**
    	 * 获取请求参数
    	 * 
    	 * @return 请求参数-表名
    	 */
    	public static String getRequestData() {
    		return REQUEST_DATA.get();
    	}
    
    	/**
    	 * 移除获取请求参数(表名)
    	 */
    	public static void remove() {
    		REQUEST_DATA.remove();
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.2 注入动态表名插件

    MybatisPlusConfig配置中添加动态表名 DynamicTableNameInnerInterceptor插件。

    使用多个功能插件时注意顺序关系,官方建议使用如下顺序:

    • 多租户,动态表名
    • 分页,乐观锁
    • sql 性能规范,防止全表更新与删除

    总结:对 sql 进行单次改造的优先放入,不对 sql 进行改造的最后放入。

    @Configuration
    public class MyBatisPlusConfig {
    
        /**
         * 注册插件
         */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    
            //1.添加动态表名插件
            DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
            dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> { //匿名内部类
                String requestTableName = RequestDynamicTableNameHelper.getRequestData();
                // 如果不为空,使用动态表名。
                if(StringUtils.isNotBlank(requestTableName)){
                    RequestDynamicTableNameHelper.remove();
                    return requestTableName;
                }
                return tableName;
            });
            interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
    
            // 2.添加分页插件
            PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
            // 设置数据库方言类型
            pageInterceptor.setDbType(DbType.MYSQL);
            // 下面配置根据需求自行设置
            // 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认false
            pageInterceptor.setOverflow(false);
            // 单页分页条数限制,默认无限制
            pageInterceptor.setMaxLimit(500L);
            interceptor.addInnerInterceptor(pageInterceptor);
    
            //3.乐观锁插件
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            return interceptor;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    2.3 service类

    创建三个表:

    DROP TABLE IF EXISTS `t_dynamic_demo`;
    CREATE TABLE t_dynamic_demo
    (
    	id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    	PRIMARY KEY (id)
    );
    
    DROP TABLE IF EXISTS `t_dynamic_demo_1`;
    CREATE TABLE t_dynamic_demo_1
    (
    	id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    	PRIMARY KEY (id)
    );
    
    DROP TABLE IF EXISTS `t_dynamic_demo_2`;
    CREATE TABLE t_dynamic_demo_2
    (
    	id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    	PRIMARY KEY (id)
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    mapper和实体类与之前的单表写法是一样。这里只需要生成 t_dynamic_demo表的代码即可。

    然后在 service类中我们加入 动态表名请求的方法即可。

    public interface DynamicDemoService extends IService<DynamicDemoDO> {
    
        void save(String dynamicTableName, DynamicDemoDO dynamicDemoDO);
    
        void updateById(String dynamicTableName, DynamicDemoDO dynamicDemoDO);
    
        void deleteById(String dynamicTableName, Long id);
    
        DynamicDemoDO getById(String dynamicTableName, Long id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @Service
    public class DynamicDemoServiceImpl extends ServiceImpl<DynamicDemoMapper, DynamicDemoDO> implements DynamicDemoService {
    
        @Autowired
        private DynamicDemoMapper dynamicDemoMapper;
    
        @Override
        public void save(String dynamicTableName, DynamicDemoDO dynamicDemoDO) {
            //将动态表名放到请求参数中(表名)
            if(StringUtils.isNotBlank(dynamicTableName)){
                RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
            }
            //和以前使用一样
            dynamicDemoMapper.insert(dynamicDemoDO);
        }
    
        @Override
        public void updateById(String dynamicTableName, DynamicDemoDO dynamicDemoDO) {
            if(StringUtils.isNotBlank(dynamicTableName)){
                RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
            }
            dynamicDemoMapper.updateById(dynamicDemoDO);
        }
    
        @Override
        public void deleteById(String dynamicTableName, Long id) {
            if(StringUtils.isNotBlank(dynamicTableName)){
                RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
            }
            dynamicDemoMapper.deleteById(id);
    
        }
    
        @Override
        public DynamicDemoDO getById(String dynamicTableName, Long id) {
            if(StringUtils.isNotBlank(dynamicTableName)){
                RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
            }
            return dynamicDemoMapper.selectById(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2.4 测试类

        @Autowired
        private DynamicDemoService dynamicDemoService;
    
        @Test
        public void testSave(){
            DynamicDemoDO dynamicDemoDO = new DynamicDemoDO();
            dynamicDemoDO.setName("dynamicDemoDO");
            dynamicDemoDO.setAge(18);
            dynamicDemoDO.setEmail("setEmail   111");
    
    
            dynamicDemoService.save(dynamicDemoDO);
            /**
             * 使用动态表名时,数据库的id自增,同一个请求不能同时插入同一个表的两条记录。
             * Duplicate entry '1' for key 't_dynamic_demo.PRIMARY'
             */
            //dynamicDemoService.save(dynamicDemoDO);
            dynamicDemoDO.setName("dynamicDemoDO_111");
            dynamicDemoService.save("t_dynamic_demo_1", dynamicDemoDO);
            dynamicDemoDO.setName("dynamicDemoDO_222");
            dynamicDemoService.save("t_dynamic_demo_2", dynamicDemoDO);
        }
    
        @Test
        public void testUpdateById(){
            DynamicDemoDO dynamicDemoDO = new DynamicDemoDO();
            dynamicDemoDO.setId(1L);
            dynamicDemoDO.setName("dynamicDemoDO_11111_update");
            dynamicDemoDO.setEmail("setEmail   111update");
    
            dynamicDemoService.save("t_dynamic_demo_1", dynamicDemoDO);
        }
    
        @Test
        public void testDeleteById(){
            dynamicDemoService.getById("t_dynamic_demo_1", 1L);
        }
    
        @Test
        public void testGetById(){
            DynamicDemoDO t_dynamic_demo_1 = dynamicDemoService.getById("t_dynamic_demo_1", 1L);
            DynamicDemoDO t_dynamic_demo_2 = dynamicDemoService.getById("t_dynamic_demo_2", 1L);
    
            System.out.println("t_dynamic_demo_1 ->" + t_dynamic_demo_1);
            System.out.println("t_dynamic_demo_2 ->" + t_dynamic_demo_1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    1)保存
    在这里插入图片描述
    2)获取
    在这里插入图片描述
    注意:上面测试时,连续保存两条记录,报错了。但是我在使用下面方式时操作OK的。

        @Override
        public void batchSaveDynamicDemo(String dynamicTableName, UserDO userDO, List<DynamicDemoDO> dynamicDemoList) {
            int insert = userMapper.insert(userDO);
    
            for (DynamicDemoDO dynamicDemoDO : dynamicDemoList) {
                if(StringUtils.isNotBlank(dynamicTableName)){
                    RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
                }
                dynamicDemoService.save(dynamicTableName, dynamicDemoDO);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    – 求知若饥,虚心若愚。

  • 相关阅读:
    BBRv2 Cruise 阶段的 inflight 补偿
    pip某些包发生SSL错误
    【Linux】安装配置虚拟机及虚拟机操作系统的安装
    python openai宠物名字生成器
    分布式定时任务系列10:XXL-job源码分析之路由策略
    gitLab更新11.11.3->16.1.5
    vue3项目服务器静态文件部署增加指定路由地址完整实现
    算法题练习——JS Node+python题解合并k个已排序的链表及链表的奇偶重排
    App的回归测试,有什么高效的测试方法?
    【面试题精讲】SpringTemplate使用
  • 原文地址:https://blog.csdn.net/qq_42402854/article/details/126714432