數據分表Mybatis Plus動態表名最優方案的探索

来源:https://www.cnblogs.com/zimug/archive/2022/08/12/16580063.html
-Advertisement-
Play Games

一、應用場景 大家在使用Mybatis進行開發的時候,經常會遇到一種情況:按照月份month將數據放在不同的表裡面,查詢數據的時候需要跟不同的月份month去查詢不同的表。 但是我們都知道,Mybatis是ORM持久層框架,即:實體關係映射,實體Object與資料庫表之間是存在一一對應的映射關係。比 ...


一、應用場景

大家在使用Mybatis進行開發的時候,經常會遇到一種情況:按照月份month將數據放在不同的表裡面,查詢數據的時候需要跟不同的月份month去查詢不同的表。

但是我們都知道,Mybatis是ORM持久層框架,即:實體關係映射,實體Object與資料庫表之間是存在一一對應的映射關係。比如:

@Data
public class Student {
    private Integer id;
    private String stuName;
    private Integer age;
}

表結構

CREATE TABLE `student` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `stu_name` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT '姓名',
    `age` INT(11) NOT NULL COMMENT '年齡',
    PRIMARY KEY (`id`)
)
COMMENT='學生表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

Student 實體類與student表是一一對應的關係,如果我們希望將學員表按照月份進行分表,比如:student_202206、student_202207、student_202208,即產生了一個實體類及其Mapper需要操作多個資料庫分月表,這種情況在Mybatis plus下我們該如何操作數據呢? 其實方法有很多,我將我實踐中總結出的最優方案給大家進行說明。

二、動態表名處理器介面實現

為了處理上述類似的問題,mybatis plus提供了動態表名處理器介面TableNameHandler,我們只需要實現這個介面,並將這個介面應用配置生效,即可實現動態表名。

需要註意的是:

  • 在mybatis plus 3.4版本之前,動態表名處理器介面是ITableNameHandler, 需要配合mybatis plus分頁插件一起使用才能生效。我們這裡只介紹3.4版本之後的實現方式。
  • 在mybatis plus 3.4.3.2 作廢該的方式:dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map); 大家如果見到這種方式實現的動態表名,也是過時的實現方法,新版本中該方法已經刪除。

經過我一段時間的實踐總結,我的實現類如下(基於mybatis plus 3.4.3.2之後的版本):

import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;

import java.util.Arrays;
import java.util.List;

/**
 * 按月份參數,組成動態表名
 */
public class MonthTableNameHandler implements TableNameHandler {

    //用於記錄哪些表可以使用該月份動態表名處理器(即哪些表按月分表)
    private List<String> tableNames;
    //構造函數,構造動態表名處理器的時候,傳遞tableNames參數
    public MonthTableNameHandler(String ...tableNames) {
        this.tableNames = Arrays.asList(tableNames);
    }

    //每個請求線程維護一個month數據,避免多線程數據衝突。所以使用ThreadLocal
    private static final ThreadLocal<String> MONTH_DATA = new ThreadLocal<>();
    //設置請求線程的month數據
    public static void setData(String month) {
        MONTH_DATA.set(month);
    }
    //刪除當前請求線程的month數據
    public static void removeData() {
        MONTH_DATA.remove();
    }

    //動態表名介面實現方法
    @Override
    public String dynamicTableName(String sql, String tableName) {
        if (this.tableNames.contains(tableName)){
            return tableName + "_" + MONTH_DATA.get();  //表名增加月份尾碼
        }else{
            return tableName;   //表名原樣返回
        }
    }
}

大家先對上面的代碼有一個基礎瞭解,看了下麵的測試過程,再回頭看上面的代碼中的註釋,就比較好理解了。表名處理器寫好了之後,我們要讓它生效,還需要做如下的配置。配置內容照葫蘆畫瓢就可以了。需要關註的部分,我都已經給大家添加了註釋。

@Configuration
@MapperScan("com.zimug")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler(
                //可以傳多個表名參數,指定哪些表使用MonthTableNameHandler處理表名稱
                new MonthTableNameHandler("student","teacher") 
        );
        //以攔截器的方式處理表名稱
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        //可以傳遞多個攔截器,即:可以傳遞多個表名處理器TableNameHandler
        //interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        return interceptor;
    }
}

三、測試實現效果

首先創建一個StudentMapper ,預設情況下StudentMapper 只能操作student表,不能操作student_YYYYMM表。

@Mapper
public interface StudentMapper extends BaseMapper<Student> {}

下麵我們來寫一個單元測試用例,該測試用例test函數模擬一次請求訪問的Controller或者service函數。

@SpringBootTest
class DynamicTableNameTest {
    @Resource
    private StudentMapper studentMapper;

    @Test
    void test() {
        //執行數據操作之前設置月份(實際場景下該參數從請求參數中解析)
        MonthTableNameHandler.setData("202208");
        studentMapper.selectById(1); //以id=2查詢student_202208這張表
        //閱後即焚,將ThreadLocal當前請求線程的數據移除
        MonthTableNameHandler.removeData();
    }
}

當我們執行這個單元測試用例的時候,我們發現控制台列印出如下信息,註意看SQL的部分,真的是去查詢student_202208這張表了,而不是student表。這說明我們的動態表名實現是成功的。

歡迎關註我的公告號:字母哥雜談,回覆003贈送作者專欄《docker修煉之道》的PDF版本,30餘篇精品docker文章。字母哥博客:zimug.com


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 多商戶商城系統,也稱為B2B2C(BBC)平臺電商模式多商家商城系統。可以快速幫助企業搭建類似拼多多/京東/天貓/淘寶的綜合商城。 多商戶商城系統支持商家入駐加盟,同時滿足平臺自營、旗艦店等多種經營方式。平臺可以通過收取商家入駐費,訂單交易服務費,提現手續費,簡訊通道費等多手段方式,實現整體盈利。 ...
  • 1、前言 在自動化測試過程中經常需要進行初始化和後期處理等工作,如電商加購物車測試需要先登錄,測試完畢需要關閉瀏覽器等。Pytest提供了5種類型的setup和teardown的方法,具體如下: 模塊級別:setup_module,teardown_module 函數級別:setup_functio ...
  • 一、簡介 1.什麼是MyBatis MyBatis 是一款優秀的持久層框架 它支持自定義 SQL、存儲過程以及高級映射。 MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。 MyBatis 可以通過簡單的 XML 或註解來配置和映射原始類型、介面和 Java POJO( ...
  • 在一個項目的開發過程中,通常伴隨著多套環境:本地環境 local、開發環境 dev、集成測試環境 test、用戶接受測試環境 uat、預生產環境 pre、生產環境 prod。本節的內容有些脫離真實企業開發,因為在真實的企業開發中,不會只開發一個獨立的服務,而是多個微服務。發展至今,雲原生也越來越普遍... ...
  • 《Python編程從入門到實踐》(第二版)免費下載地址~~ 內容簡介 · · · · · · 本書是針對所有層次Python讀者而作的Python入門書。全書分兩部分:第一部分介紹用Python編程所必須瞭解的基本概念,包括Matplotlib等強大的Python庫和工具,以及列表、字典、if語句、 ...
  • 首先你需要安裝RabbitMQ,安裝教程可百度查下資料即可,不做贅述,敬請諒解 啟動RabbitMQ RabbitMQ可以算是一個非同步消息隊列,在實際的開發項目中,一般是以工具模塊的方式創建,像一些SpringBoot工程所需要的基本依賴都是會有的 說明:關鍵在於誰是消息的生產者、消息的消費者;另外 ...
  • 很多小伙伴都喜歡小游戲源碼,想學一手Python做小游戲,問我做游戲難不難,要怎麼做,接下來我就介紹一下,如何用Python做游戲。 游戲演示 2048小游戲 表白彈窗 貪吃蛇 五子棋 俄羅斯方塊 超多小游戲,讓你一個爽個夠! 用PyGame做游戲非常簡單,我們今天第一篇文章,讓大家實現一個可以在地 ...
  • 我國目前並未出台專門針對網路爬蟲技術的法律規範,但在司法實踐中,相關判決已屢見不鮮,K 哥特設了“K哥爬蟲普法”專欄,本欄目通過對真實案例的分析,旨在提高廣大爬蟲工程師的法律意識,知曉如何合法合規利用爬蟲技術,警鐘長鳴,做一個守法、護法、有原則的技術人員。 案情介紹 深圳市快鴿互聯網科技有限公司 2 ...
一周排行
    -Advertisement-
    Play Games
  • 一、openKylin簡介 openKylin(開放麒麟) 社區是在開源、自願、平等和協作的基礎上,由基礎軟硬體企業、非營利性組織、社團組織、高等院校、科研機構和個人開發者共同創立的一個開源社區,致力於通過開源、開放的社區合作,構建桌面操作系統開源社區,推動Linux開源技術及其軟硬體生態繁榮發展。 ...
  • 簡介 Flurl是一個用於構建基於HTTP請求的C#代碼的庫。它的主要目的是簡化和優雅地處理網路請求(只用很少的代碼完成請求)。Flurl提供了一種簡單的方法來構建GET、POST、PUT等類型的請求,以及處理響應和異常。它還提供了一些高級功能,如鏈式調用、緩存請求結果、自動重定向等。本文將介紹Fl ...
  • 一:背景 1. 講故事 最近也挺奇怪,看到了兩起 CPU 爆高的案例,且誘因也是一致的,覺得有一些代表性,合併分享出來幫助大家來避坑吧,閑話不多說,直接上 windbg 分析。 二:WinDbg 分析 1. CPU 真的爆高嗎 這裡要提醒一下,別人說爆高不一定真的就是爆高,我們一定要拿數據說話,可以 ...
  • 剛開始寫文章,封裝Base基類的時候,添加了trycatch異常塊,不過當時沒有去記錄日誌,直接return了。有小伙伴勸我不要吃了Exception 其實沒有啦,項目剛開始,我覺得先做好整體結構比較好。像是蓋樓一樣。先把樓體建造出來,然後再一步一步的美化完善。 基礎的倉儲模式已經ok,Autofa ...
  • 框架目標 什麼是框架,框架能做到什麼? 把一個方向的技術研發做封裝,具備通用性,讓使用框架的開發者用起來很輕鬆。 屬性: 通用性 健壯性 穩定性 擴展性 高性能 組件化 跨平臺 從零開始-搭建框架 建立項目 主鍵查詢功能開發 綁定實體 一步一步的給大家推導: 一邊寫一邊測試 從零開始--搭建框架 1 ...
  • 大家好,我是沙漠盡頭的狼。 本方首發於Dotnet9,介紹使用dnSpy調試第三方.NET庫源碼,行文目錄: 安裝dnSpy 編寫示常式序 調試示常式序 調試.NET庫原生方法 總結 1. 安裝dnSpy dnSpy是一款功能強大的.NET程式反編譯工具,可以對.NET程式進行反編譯,代替庫文檔的功 ...
  • 在`Windows`操作系統中,每個進程的虛擬地址空間都被劃分為若幹記憶體塊,每個記憶體塊都具有一些屬性,如記憶體大小、保護模式、類型等。這些屬性可以通過`VirtualQueryEx`函數查詢得到。該函數可用於查詢進程虛擬地址空間中的記憶體信息的函數。它的作用類似於`Windows`操作系統中的`Task... ...
  • 背景介紹 1,最近有一個大數據量插入的操作入庫的業務場景,需要先做一些其他修改操作,然後在執行插入操作,由於插入數據可能會很多,用到多線程去拆分數據並行處理來提高響應時間,如果有一個線程執行失敗,則全部回滾。 2,在spring中可以使用@Transactional註解去控制事務,使出現異常時會進行 ...
  • 線程(thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際 運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線 程並行執行不同的任務。 ...
  • 發現Java 21的StringBuilder和StringBuffer中多了repeat方法: /** * @throws IllegalArgumentException {@inheritDoc} * * @since 21 */ @Override public StringBuilder ...