亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

為什么要分表

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/**
 * 按天分表解析
 */
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取模表名處理器

再來看下按id取模表名處理器的實現(xiàn),這個處理器相對日期處理就要復(fù)雜一些,主要原因為需要動態(tài)傳入用于分表的id值。

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

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

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

具體實現(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("請設(shè)置id值");
    } else {
      String suffix = String.valueOf(idValue % mod);
      //這里清除ThreadLocal的值,防止線程復(fù)用出現(xiàn)問題
      id.set(null);
      return tableName + "_" + suffix;
    }
  }
}

3.加載表名處理器

表名處理器實際是mybatis-plus的插件,需要在初始化時創(chuàng)建實例并加載。因為系統(tǒng)中存在兩種分表類型,在初始化時可以指定每張表使用的表名處理器。具體實現(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è)置對應(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中使用

下面通過controller中的三個接口,展示下使用方式:

@RestController
public class TableTestController {
  @Resource
  IUserDailyRecordService userDailyRecordService;

  @Resource
  IUserConsumeFlowService userConsumeFlowService;

  @GetMapping("user/record/today")
  public CommonResVo<UserDailyRecord> getRecordToday(Integer userId) throws Exception {
    //這里在查詢時,會根據(jù)系統(tǒng)當(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);
  }
}

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

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

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

相關(guān)文章

  • java操作excel的方法

    java操作excel的方法

    這篇文章主要介紹了java操作excel的方法,實例分析了java針對excel文件的讀寫、打開、保存等操作技巧,需要的朋友可以參考下
    2015-07-07
  • 關(guān)于elasticsearch的match_phrase_prefix查詢詳解

    關(guān)于elasticsearch的match_phrase_prefix查詢詳解

    這篇文章主要介紹了關(guān)于elasticsearch的match_phrase_prefix查詢問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 解決Springboot中@Async注解獲取不到上下文信息問題

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

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

    java拓展集合工具類CollectionUtils

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

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

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

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

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

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

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

    深入理解Java 線程通信

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

    全面解析Spring Security 過濾器鏈的機制和特性

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

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

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

最新評論