欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis-plus使用TableNameHandler分表詳解(附完整示例源碼)

 更新時(shí)間:2021年01月26日 10:23:21   作者:dothetrick  
這篇文章主要介紹了Mybatis-plus使用TableNameHandler分表詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

為什么要分表

Mysql是當(dāng)前互聯(lián)網(wǎng)系統(tǒng)中使用非常廣泛的關(guān)系數(shù)據(jù)庫(kù),具有ACID的特性。

但是mysql的單表性能會(huì)受到表中數(shù)據(jù)量的限制,主要原因是B+樹索引過(guò)大導(dǎo)致查詢時(shí)索引無(wú)法全部加載到內(nèi)存。讀取磁盤的次數(shù)變多,而磁盤的每次讀取對(duì)性能都有很大的影響。

這時(shí)一個(gè)簡(jiǎn)單可行的方案就是分表(當(dāng)然土豪也可以堆硬件),將一張數(shù)據(jù)量龐大的表的數(shù)據(jù),拆分到多個(gè)表中,這同時(shí)也減少了B+樹索引的大小,減少磁盤讀取次數(shù),提高性能。

兩種基礎(chǔ)分表邏輯

說(shuō)完了為什么要分表,下面聊聊業(yè)務(wù)開發(fā)中常見的兩種基礎(chǔ)的分表邏輯。

按日期分表
這種方式通常會(huì)在表名的最后加上年月日,主要適用于按日期劃分的統(tǒng)計(jì)數(shù)據(jù)或操作記錄。在線實(shí)時(shí)展示的只有最近表中的數(shù)據(jù),其他數(shù)據(jù)用于離線統(tǒng)計(jì)等。

按id取模分表
這種方式需要一個(gè)id生成器,例如snowflake id或分布式id服務(wù)。它保證了相同id的數(shù)據(jù)都在一張表中,主要適用于保存用戶基礎(chǔ)信息,系統(tǒng)中的資源信息,購(gòu)買記錄等。當(dāng)然這種分表方式擴(kuò)展性較差,后期數(shù)據(jù)持續(xù)增多后需要按id大小分庫(kù)再分表處理。

下面看下這兩種分表邏輯在mybatis-plus中的實(shí)現(xiàn)。

Mybatis-plus中的分表實(shí)現(xiàn)

說(shuō)到j(luò)ava的分表中間件,可能有人會(huì)想到sharding-jdbc,作為使用很廣泛的一個(gè)分表中間件,功能也比較完善,但是使用它需要引入額外的jar包和增加學(xué)習(xí)成本。

實(shí)際上mybatis-plus本身就提供了一個(gè)分表的解決方案,配置使用都很簡(jiǎn)單,適合快速開發(fā)系統(tǒng)。

動(dòng)態(tài)表名處理器

沒錯(cuò),mybatis-plus提供了動(dòng)態(tài)表名處理器接口TableNameHandler,只需要在系統(tǒng)中實(shí)現(xiàn)該接口,并作為插件加載到mybatis-plus中就可以使用,下面來(lái)看下詳細(xì)的步驟。

3.4版本之前的動(dòng)態(tài)表名接口是ITableNameHandler,需要和分頁(yè)插件配合使用。
3.4版本新增了TableNameHandler,在方法參數(shù)上取消了MetaObject。這里用最新的版本為例,使用方式差別不大。

假設(shè)我們的系統(tǒng)中有兩種分表方式,按日期分表和按id取模分表。通過(guò)四個(gè)步驟來(lái)看下具體的使用示例。

1.創(chuàng)建日期表名處理器

先來(lái)看下日期處理的表名處理器,實(shí)現(xiàn)TableNameHandler接口后,在dynamicTableName方法中實(shí)現(xiàn)動(dòng)態(tài)生成表名的邏輯,方法的返回值就是查詢時(shí)要使用的表名。

/**
 * 按天分表解析
 */
public class DaysTableNameParser implements TableNameHandler {

  @Override
  public String dynamicTableName(String sql, String tableName) {
    String dateDay = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    return tableName + "_" + dateDay;
  }
}

2.創(chuàng)建id取模表名處理器

再來(lái)看下按id取模表名處理器的實(shí)現(xiàn),這個(gè)處理器相對(duì)日期處理就要復(fù)雜一些,主要原因?yàn)樾枰獎(jiǎng)討B(tài)傳入用于分表的id值。

在之前的版本中可以在方法中通過(guò)解析MetaObject中帶有的sql查詢信息,獲取分表使用的值。但是這種方式比較復(fù)雜,對(duì)于不同的QueryMapper分析的方式不同,比較容易出錯(cuò)。新版本中的方法取消了MetaObject參數(shù),需要使用其他方式傳入。

需要注意的是,表名處理器是作為mybatis-plus的插件,在項(xiàng)目啟動(dòng)時(shí)實(shí)例化的。這意味著,在運(yùn)行過(guò)程中只有一個(gè)對(duì)象,多線程處理過(guò)程中,一個(gè)線程對(duì)參數(shù)的修改,會(huì)影響到其他線程。為了解決這個(gè)問題,可以使用ThreadLocal來(lái)定義參數(shù)。

由于現(xiàn)在的框架中大部分會(huì)使用線程池,例如springboot web項(xiàng)目中的tomcat。所以在每次使用后,需要手動(dòng)清除本次數(shù)據(jù),防止線程復(fù)用時(shí)的影響。

具體實(shí)現(xiàn)如下:

/**
 * 按id取模分表處理器
 */
public class IdModTableNameParser implements TableNameHandler {
  private Integer mod;

  //使用ThreadLocal防止多線程相互影響
  private static ThreadLocal<Integer> id = new ThreadLocal<Integer>();

  public static void setId(Integer idValue) {
    id.set(idValue);
  }

  IdModTableNameParser(Integer modValue) {
    mod = modValue;
  }

  @Override
  public String dynamicTableName(String sql, String tableName) {
    Integer idValue = id.get();
    if (idValue == null) {
      throw new RuntimeException("請(qǐng)?jiān)O(shè)置id值");
    } else {
      String suffix = String.valueOf(idValue % mod);
      //這里清除ThreadLocal的值,防止線程復(fù)用出現(xiàn)問題
      id.set(null);
      return tableName + "_" + suffix;
    }
  }
}

3.加載表名處理器

表名處理器實(shí)際是mybatis-plus的插件,需要在初始化時(shí)創(chuàng)建實(shí)例并加載。因?yàn)橄到y(tǒng)中存在兩種分表類型,在初始化時(shí)可以指定每張表使用的表名處理器。具體實(shí)現(xiàn)如下:

@Configuration
@MapperScan(basePackages = "com.yourcom.proname.repository.mapper.mainDb*", sqlSessionFactoryRef = "mainSqlSessionFactory")
public class MainDb {
  @Bean(name = "mainDataSource")
  @ConfigurationProperties(prefix = "dbconfig.maindb")
  public DataSource druidDataSource() {
    return DruidDataSourceBuilder.create().build();
  }

  @Bean(name = "mainTransactionManager")
  public DataSourceTransactionManager masterTransactionManager(@Qualifier(value = "mainDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }

  @Bean(name = "mainSqlSessionFactory")
  @ConfigurationPropertiesBinding()
  public SqlSessionFactory sqlSessionFactory(@Qualifier(value = "mainDataSource") DataSource dataSource) throws Exception {
    MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
     //加載插件
    factoryBean.setPlugins(mybatisPlusInterceptor());
    return factoryBean.getObject();
  }

  @Bean
  public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
    HashMap<String, TableNameHandler> map = new HashMap<String, TableNameHandler>();

    //這里為不同的表設(shè)置對(duì)應(yīng)表名處理器
    map.put("user_daily_record", new DaysTableNameParser());
    map.put("user_consume_flow", new IdModTableNameParser(10));

    dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
    interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
    return interceptor;
  }
}

4.在controller中使用

下面通過(guò)controller中的三個(gè)接口,展示下使用方式:

@RestController
public class TableTestController {
  @Resource
  IUserDailyRecordService userDailyRecordService;

  @Resource
  IUserConsumeFlowService userConsumeFlowService;

  @GetMapping("user/record/today")
  public CommonResVo<UserDailyRecord> getRecordToday(Integer userId) throws Exception {
    //這里在查詢時(shí),會(huì)根據(jù)系統(tǒng)當(dāng)前時(shí)間,自動(dòng)生成當(dāng)天的表名
    UserDailyRecord userDailyRecord = userDailyRecordService.getOne(new LambdaQueryWrapper<UserDailyRecord>().eq(UserDailyRecord::getUserId, userId));
    return CommonResVo.success(userDailyRecord);
  }

  @GetMapping("user/consume/flow")
  public CommonResVo<List<UserConsumeFlow>> getConsumeFlow(Integer userId) throws Exception {
    //設(shè)置用于分表的id值
    IdModTableNameParser.setId(userId);
    List<UserConsumeFlow> userConsumeFlowList = userConsumeFlowService.list(new LambdaQueryWrapper<UserConsumeFlow>().eq(UserConsumeFlow::getUserId, userId));
    return CommonResVo.success(userConsumeFlowList);
  }

  /**
   * 新增數(shù)據(jù)
   */
  @PostMapping("user/consume/flow")
  public CommonResVo<Boolean> addConsumeFlow(@RequestBody UserConsumeFlow userConsumeFlow) throws Exception {
    Integer userId = userConsumeFlow.getUserId();
    //設(shè)置用于分表的id值
    IdModTableNameParser.setId(userId);
    userConsumeFlowService.save(userConsumeFlow);
    return CommonResVo.success(true);
  }
}

這篇對(duì)mybatis-plus動(dòng)態(tài)表名處理器的介紹,通過(guò)實(shí)現(xiàn)TableNameHandler接口,可以按實(shí)際情況靈活定義表名的生成規(guī)則,希望對(duì)大家有幫助。

項(xiàng)目完整示例地址:https://gitee.com/dothetrick/web-demo/tree/tabel-shading

到此這篇關(guān)于Mybatis-plus使用TableNameHandler分表詳解(附完整示例源碼)的文章就介紹到這了,更多相關(guān)Mybatis-plus TableNameHandler分表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決Springboot中@Async注解獲取不到上下文信息問題

    解決Springboot中@Async注解獲取不到上下文信息問題

    實(shí)際開發(fā)中我們經(jīng)常需要通過(guò)spring上下文獲取一些配置信息,本文主要介紹了解決Springboot中@Async注解獲取不到上下文信息問題,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • java拓展集合工具類CollectionUtils

    java拓展集合工具類CollectionUtils

    這篇文章主要為大家詳細(xì)介紹了java拓展集合工具類CollectionUtils,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • java實(shí)現(xiàn)銀行家算法(Swing界面)

    java實(shí)現(xiàn)銀行家算法(Swing界面)

    這篇文章主要為大家詳細(xì)介紹了銀行家算法的java代碼實(shí)現(xiàn),Swing寫的界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 基于Java接口回調(diào)詳解

    基于Java接口回調(diào)詳解

    這篇文章主要介紹了Java接口回調(diào)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • JVM的垃圾回收算法工作原理詳解

    JVM的垃圾回收算法工作原理詳解

    這篇文章主要介紹了JVM的垃圾回收算如何判斷對(duì)象是否可以被回收,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • 深入理解Java 線程通信

    深入理解Java 線程通信

    這篇文章主要介紹了Java 線程通信的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • 全面解析Spring Security 過(guò)濾器鏈的機(jī)制和特性

    全面解析Spring Security 過(guò)濾器鏈的機(jī)制和特性

    這篇文章主要介紹了Spring Security 過(guò)濾器鏈的機(jī)制和特性,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • JavaWeb三大組件之監(jiān)聽器Listener詳解

    JavaWeb三大組件之監(jiān)聽器Listener詳解

    這篇文章主要介紹了JavaWeb三大組件之監(jiān)聽器Listener詳解,在JavaWeb應(yīng)用程序中,Listener監(jiān)聽器是一種機(jī)制,用于監(jiān)聽和響應(yīng)特定的事件,它可以感知并響應(yīng)與應(yīng)用程序相關(guān)的事件,從而執(zhí)行相應(yīng)的邏輯處理,需要的朋友可以參考下
    2023-10-10
  • 最新評(píng)論