在数据量较大时,会选择将一张表分为多张分表保存对应数据,常见以数字为后缀为分表命名。更新插入数据时,需要指定分表写入。
示例:
原表:consume_data
分表:consume_data_01、consume_data_02、consume_data_03、consume_data_04、…
每张分表的字段都完全一致。
实体类
public class ConsumeData{
private Long id;
private String phoneNum;
private Date createTime;
}
根据实体类中的手机号作为指定分表的条件
List<ConsumeData> list = new ArrayList<>();
//按手机号的最后两位分组
Map<String, List<ConsumeData>> groupByMap = list.stream()
.collect(Collectors.groupingBy(x -> x.getPhoneNum()
.substring(x.getPhoneNum().length() - 2)));
// 遍历获取手机号最后两位以及对应的数据集合
for (Map.Entry<String, List<ConsumeData>> entry : groupByMap.entrySet()) {
String tableSuffix = entry.getKey();
List<ConsumeData> suffixList = entry.getValue();
}
根据实体类中的时间作为加入分表的条件
List<ConsumeData> list = new ArrayList<>();
// 按照年月分组 202401
Map<String, List<ConsumeData>> groupByMap = list.stream().filter(x -> x.getCreateTime() != null).collect(Collectors.groupingBy(item -> {
Date createTime = item.getCreateTime();
calender.setTime(createTime);
int year = calender.get(Calendar.YEAR);
int month = calender.get(Calendar.MONTH) + 1;
// month <10 前补0
String yearMonth = year + "" + (month < 10 ? "0" + month : month);
return yearMonth;
}));
获取年月季度
Calendar calendar = Calendar.getInstance();
// 获取当前年
int year = calendar.get(Calendar.YEAR);
// 获取当前月
int month = calendar.get(Calendar.MONTH) + 1;
// 当前季度
int quarter = (month%3 == 0)?(month/3):(month/3+1);
mapper类
void insertBatch(@Param("list") List<ConsumeData> list, @Param("tableSuffix") String tableSuffix);
xml
<insert id="insertBatch">
INSERT INTO consume_data_${tableSuffix}(consume_id,phone_num,create_time)
values
<foreach collection="list" item="item" separator=",">
(#{item.consumeId}, #{item.phoneNum}, #{item.createTime})
</foreach>
</insert>
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.ArrayList;
import java.util.List;
/**
* Mybatis Plus 配置
*
* @author ruoyi
*/
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig
{
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor()
{
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
// 乐观锁插件
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
// 阻断插件
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
// 动态表名拦截器
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
String newTable = null;
for (String table : tableList()) {
newTable = RequestDataHelper.getRequestData(table);
if (table.equals(tableName) && newTable!=null){
tableName = newTable;
break;
}
}
return tableName;
});
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
return interceptor;
}
// 设置需要动态设置表名的表
static List<String> tableList(){
List<String> tables = new ArrayList<>();
tables.add("comsume_data");
return tables;
}
/**
* 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
*/
public PaginationInnerInterceptor paginationInnerInterceptor()
{
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置数据库类型为mysql
paginationInnerInterceptor.setDbType(DbType.MYSQL);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
return paginationInnerInterceptor;
}
/**
* 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
*/
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor()
{
return new OptimisticLockerInnerInterceptor();
}
/**
* 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
*/
public BlockAttackInnerInterceptor blockAttackInnerInterceptor()
{
return new BlockAttackInnerInterceptor();
}
}
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import java.util.Map;
/**
* 请求参数传递辅助类
*/
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();
}
}
public void setTable (String month){
String table = "consume_data_" + month;
RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
put("consume_data", table);
}});
}
public void updateDataById(ConsumeData consumeData, String month) {
consumeData = new ConsumeData();
consumeData.setConsumeId(1L);
consumeData.setPhoneNum(19111111111);
consumeData.setCreateTime(new Date());
// 动态设置分表
setTable(month);
// 更新数据
this.updateById(consumeData);
}