«

springboot按月分表的方法是什么

时间:2024-6-16 06:33     作者:韩俊     分类: Java


本文小编为大家详细介绍“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 配置
mybatis-plus.configuration.call-setters-on-nulls=true
# xml 文件路径
mybatis-plus.mapper-locations=classpath*:mapping/*.xml
# entity 文件路径
mybatis-plus.type-aliases-package=com.geniuworks.bot.entity
# 打印sql语句执行日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# 需要按月分表的表名
mp.tableNames=message

3、MybatisPlusConfig实现

MybatisPlusConfig配置类实现:

package com.geniuworks.bot.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.parsers.DynamicTableNameParser;
import com.baomidou.mybatisplus.extension.parsers.ITableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.geniuworks.bot.entity.Tables;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.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.getTableNames();
            //动态表规则 初始表名+_+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 = metaObject.getOriginalObject();
        JSONObject originalObjectJSON = JSON.parseObject(JSON.toJSONString(originalObject));
        JSONObject boundSql = originalObjectJSON.getJSONObject("boundSql");
        JSONObject parameterObject = boundSql.getJSONObject("parameterObject");
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM");
        if(parameterObject.get(title) == null){
            return "";
        }
        Date date = parameterObject.getObject(title, Date.class);
        log.info("param value = " + formatter.format(date));
        return "_" + formatter.format(date);
    }
}

Tables类实现:

package com.geniuworks.bot.entity;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.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 com.geniuworks.bot.entity;

import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
    private String id;

    private String sessionId;

    private Date createdTime;

    private String content;

    // 根据该字段所在的月分,区分访问的表名
    private Date month;
}

mapper类实现:

package com.geniuworks.bot.mapper;

import com.geniuworks.bot.entity.Message;
import com.geniuworks.bot.vo.MessageVo;
import com.geniuworks.bot.vo.StatisticsVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.Date;
import java.util.List;
import java.util.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
     * @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中的字段命名。

解决方案: 梳理受到影响的代码逻辑,更新使用的字段命名。

标签: java spring

热门推荐