springboot按⽉分表的优雅实现⽅式
springboot 按⽉分表
⼀、项⽬背景
在实际⼯作中,会遇到业务⽐较集中的情况,随着时间推延,这部分业务关联的mysql表就会越来越⼤,⼗分臃肿。尽管在项⽬架构上做了读写分离,也会导致查询的时候出现⽐较慢的情况,导致线上慢查询的出现。
这种情况下导致的慢查询,单纯从sql优化的⾓度是⽆法解决的,此时我们就会⽤到分库分表。由于我们⽬前的问题是部分mysql表⽐较⼤,采⽤分表的⽅式即可解决,本⽂主要讨论分表的情况。
1、分表的⽅式
垂直分表
简单理解:把同⼀个表中的数据按列拆分到不同的表中。
所谓的垂直分表指的是将表结构按照功能模块、关系密切程度划分出来,部署到不同的库或者不同的表中。
⽔平分表
简单理解:把同⼀个表中的数据按⾏拆分到不同的表中。
所谓的⽔平分表,即将数据按照某种规则存储到不同的表中。例如⽇志表,可以使⽤按⽉或者按天分表,即每个⽉的⽇志数据单独存储在⼀张表中。这些表同时属于⼀张主表,拥有相同的表结构,但查询时可以⼤⼤减轻主表查询的负担。
⼆、代码实现
主要使⽤mybatis-plus提供的功能来实现功能。
1、pom⽂件依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
2、配置⽂件
# mybatis-plus 配置
# xml ⽂件路径
mybatis-plus.mapper-locations=classpath*:mapping/*.xml
# entity ⽂件路径
# 打印sql语句执⾏⽇志
# 需要按⽉分表的表名
mp.tableNames=message
3、MybatisPlusConfig实现
MybatisPlusConfig配置类实现:
package;
import JSON;
import JSONObject;
import DynamicTableNameParser;
import ITableNameHandler;
import PaginationInterceptor;
import Tables;
import Slf4j;
import MetaObject;
import Autowired;
import Bean;
import Configuration;
import SimpleDateFormat;
import Collections;
import Date;
import HashMap;
import List;
/**
* @Author dingws
* @PackageName
* @Package
* @Date 2022/1/5 1:53 下午
* @Version 1.0
*/
@Configuration
@Slf4j
public class MybatisPlusConfig {
@Autowired
private Tables tableNames;
/**
*
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor paginationInterceptor =new PaginationInterceptor();
DynamicTableNameParser dynamicTableNameParser =new DynamicTableNameParser();
dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2){{
//涉及表集合
List<String> tables = TableNames();
//动态表规则初始表名+_+code
tables.forEach(tableTitle ->put(tableTitle,(metaObject, sql, tableName)-> tableName + String.valueOf(getParamValue("month",metaObject))));
}});
paginationInterceptor.setSqlParserList(Collections.singletonList(dynamicTableNameParser));
return paginationInterceptor;
}
/**
*
* @param title
* @param metaObject
* @return
*/
private Object getParamValue(String title, MetaObject metaObject){
//获取参数
Object originalObject = OriginalObject();
JSONObject originalObjectJSON = JSON.JSONString(originalObject));
JSONObject boundSql = JSONObject("boundSql");
JSONObject parameterObject = JSONObject("parameterObject");
SimpleDateFormat formatter =new SimpleDateFormat("yyyy_MM");
(title)==null){
return"";
}
Date date = Object(title, Date.class);
Date date = Object(title, Date.class);
log.info("param value = "+ formatter.format(date));
return"_"+ formatter.format(date);
}
}
Tables类实现:
package;
import Data;
import ConfigurationProperties;
import Configuration;
import List;
/
**
* @Author dingws
* @PackageName
* @Package
* @Date 2022/1/5 2:18 下午
* @Version 1.0
*/
@Configuration
@ConfigurationProperties("mp")
@Data
public class Tables {
private List<String> tableNames;
}
4、优雅的使⽤
在使⽤的时候,只需要在mysql表对应的entity⾥添加⼀个字段month即可。
如果month不为空就会按照month的⽇期所在的⽉份对数据库表明进⾏动态拼接。如果month为空则不进⾏拼接,直接访问总表。entity类实现:
package;
import Date;
import AllArgsConstructor;
import Data;
import NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private String id;
private String sessionId;
private Date createdTime;
private String content;
// 根据该字段所在的⽉分,区分访问的表名
private Date month;
}
mapper类实现:
package;
import Message;
import MessageVo;
import StatisticsVo;
import Mapper;
import Param;
import Select;
import Date;
import List;
import Map;
@Mapper
public interface MessageMapper {
/**
* insert record to table
* @param record the record
* @return insert count
*/
int insert(Message record);
/**
* insert record to table selective
springboot结构
* @param record the record
* @return insert count
*/
int insertSelective(Message record);
/**
* update record selective
* @param record the updated record
* @return update count
*/
int updateByPrimaryKeySelective(Message record);
/**
* update record
* @param record the updated record
* @return update count
*/
int updateByPrimaryKey(Message record);
5、mysql表名拆分
需要⼿动把当年需要的数据库⼿动创建出来,命名规则对应MybatisPlusConfig类中的拼接规则。
三、遇到的问题
由于我⼀直⽤的是mybatis组件,需要升级为mybatis-plus,在升级的过程中出现如下的问题。1、Invalid bound statement (not found)
问题原因:
pom⽂件依赖的是mybatis-plus,配置⽂件中使⽤的是mybatis的配置,导致mybatis加载失败。解决⽅法:
把配置⽂件的mybatis配置改为mybatis-plus配置
2、resultType=“java.util.Map”,返回字段名被包装
问题原因:
在未升级成mybatis-plus之前,可以直接放回数据库中的字段命名。升级之后,mybatis-plus将放回字段⾃动映射为entity中的字段命名。
解决⽅案:
梳理受到影响的代码逻辑,更新使⽤的字段命名。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。