您当前的位置: 首页 >  mybatis

Charge8

暂无认证

  • 5浏览

    0关注

    447博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

MyBatis-Plus动态表名插件使用

Charge8 发布时间:2022-09-05 22:04:46 ,浏览量:5

一、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 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();
	}

}
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;
    }

}
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)
);

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

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

public interface DynamicDemoService extends IService {

    void save(String dynamicTableName, DynamicDemoDO dynamicDemoDO);

    void updateById(String dynamicTableName, DynamicDemoDO dynamicDemoDO);

    void deleteById(String dynamicTableName, Long id);

    DynamicDemoDO getById(String dynamicTableName, Long id);

}
@Service
public class DynamicDemoServiceImpl extends ServiceImpl 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);
    }
}
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)获取 在这里插入图片描述 注意:上面测试时,连续保存两条记录,报错了。但是我在使用下面方式时操作OK的。

    @Override
    public void batchSaveDynamicDemo(String dynamicTableName, UserDO userDO, List dynamicDemoList) {
        int insert = userMapper.insert(userDO);

        for (DynamicDemoDO dynamicDemoDO : dynamicDemoList) {
            if(StringUtils.isNotBlank(dynamicTableName)){
                RequestDynamicTableNameHelper.setRequestData(dynamicTableName);
            }
            dynamicDemoService.save(dynamicTableName, dynamicDemoDO);
        }
    }

– 求知若饥,虚心若愚。

关注
打赏
1664721914
查看更多评论
立即登录/注册

微信扫码登录

0.0462s