关于java+mybatis进行策略分表

项目场景:

一个小单体springboot项目,核心业务为计算电力线路损耗,由于一条线路中有几百个元素(终端,表计),每天每一个元素按照规则上报数据,数据内容是一整天每15分钟时间点监测的电流数据,元素太多导致上报的数据也多,这里就需要考虑针对线路进行分表,主要技术是 java+mybatisplus

业务描述

根据线路进行分表,线路表engineering e,终端电流freezing_data f,表计电流meter_data m,效果是
e表插入一条id为123的数据,f表和m表就要新加一个表并且拼接123的后缀=》freezing_data_123,meter_data_123,并且在查询时要自动通过条件查询终端所在的线路并通过线路id找到数据表。


实现思路:

1.首先engineering对象添加时,自动创建两个数据表
这里mapper 可以传表名,tableName就是 表名_id 
    int createTable(@Param("tableName") String tableName);
<insert id="createTable"  parameterType="String">
    CREATE TABLE ${tableName}
    (	ID VARCHAR2(32) NOT NULL ENABLE,
         METER_CURRENT VARCHAR2(32),
         FREEZING_TIME VARCHAR2(32),
         METERBAR_CODE VARCHAR2(128),
         PHASE_TYPE VARCHAR2(32),
         SAVE_TIME VARCHAR2(32),
         CREATE_TIME VARCHAR2(32),
         PRIMARY KEY (ID)
    )
</insert>
创建表是创建完了,下一步如何在查询时定位到查询表呢
这里我们就需要考虑mybatis的sql执行过程,首先一定是有个拦截器,毕竟一个实体对应一个表
不能无限去添加实体。 这里我们需要找到那个扫描mapper的mp配置类 准备自己添加个拦截器。
再添加拦截器之前肯定有个类需要存 id 以备后续动态拼接
//  这里我们添加一个线程局部变量 防止抢占线路id
public class RequestDataHelper {
    /**
     * 请求参数存取
     */
    private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();

    /**
     * 设置请求参数
     *
     * @param requestData 请求参数 MAP 对象
     */
    public static void setRequestData(Map<String, Object> requestData) {
        REQUEST_DATA.set(requestData);
    }

    /**
     * 获取请求参数
     *
     * @param param 请求参数
     * @return 请求参数 MAP 对象
     */
    public static <T> T getRequestData(String param) {
        Map<String, Object> dataMap = getRequestData();
        if (CollectionUtils.isNotEmpty(dataMap)) {
            return (T) dataMap.get(param);
        }
        return null;
    }

    /**
     * 获取请求参数
     *
     * @return 请求参数 MAP 对象
     */
    public static Map<String, Object> getRequestData() {
        return REQUEST_DATA.get();
    }
}
这里轮到拦截器部分,拦截器部分就是从线程局部变量中取出线路的id
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 新建表名拦截器
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
            // 获取参数方法
            Map<String, Object> paramMap = RequestDataHelper.getRequestData();
            if (CollectionUtils.isNotEmpty(paramMap)&&(tableName.equals("meter_data")||tableName.equals("freezing_data"))) {
                // 获取传递的参数
                String userId = (String) paramMap.get("line");
                //  ID 决定表名后缀
                String tableNameSuffix = "_" +userId;
                // 组装动态表名
                return tableName + tableNameSuffix;
            }
            return tableName;
        });
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
      
       xxx
       其他拦截器
       xxx
   
       return interceptor;
       }


拦截器写完我们怎么用呢
	我们只需要先查询出来id 然后存到这个map中然后存到线程变量中就可以了
	
	RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
						put("line",engineering.getId();
					}});
	freezingDataService.list();
	这样list在调用时会走拦截器,拦截器会返回动态表名给这个表名处理器,最终实现分表动态查询

已知缺陷:

这样动态分表的数据查询必须一条线路一条线路的查询,多条线路需要java拼接等方式。

写完发现 我所用的框架是jeecg,jeecg他本身就写了一个动态表名的拦截器,可以研究一下怎么用,思路大概都差不多

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要在Mybatis中配置分表策略和数据源路由。这里使用ShardingSphere进行分表和数据源路由的配置。 1. 添加ShardingSphere的相关依赖 ```xml <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>${shardingsphere.version}</version> </dependency> ``` 2. 配置ShardingSphere的数据源和分表策略 ```yaml spring: shardingsphere: datasource: names: ds0, ds1 ds0: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/user0?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8 username: root password: root ds1: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/user1?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8 username: root password: root sharding: tables: user: actualDataNodes: ds${0..1}.user_${0..1} tableStrategy: standard: shardingColumn: id shardingAlgorithmName: userTableShardingAlgorithm keyGenerateStrategy: column: id keyGeneratorName: snowflake defaultDatabaseStrategy: inline: shardingColumn: id algorithmExpression: ds${id % 2} shardingAlgorithms: userTableShardingAlgorithm: type: INLINE props: algorithm-expression: user_${id % 2} keyGenerators: snowflake: type: SNOWFLAKE props: worker-id: 123 ``` 3. 创建User实体类和Mapper接口 ```java @Data public class User { private Long id; private String name; private Integer age; } @Mapper public interface UserMapper { @Insert("INSERT INTO user_${id % 2}(name, age) VALUES(#{name}, #{age})") int insert(User user); } ``` 4. 创建Service层,调用Mapper插入数据 ```java @Service public class UserService { @Autowired private UserMapper userMapper; public void save(User user) { userMapper.insert(user); } } ``` 以上就是使用SpringBootMybatis实现user表分表插入用户数据的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值