首頁 > 軟體

springboot 按月分表的實現方式

2023-11-22 14:00:15

一、專案背景

在實際工作中,會遇到業務比較集中的情況,隨著時間推延,這部分業務關聯的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中的欄位命名。

解決方案: 梳理受到影響的程式碼邏輯,更新使用的欄位命名。

到此這篇關於springboot 按月分表的實現方式的文章就介紹到這了,更多相關springboot 按月分表內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com