最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)然這種分表方式擴(kuò)展性較差,后期數(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中I/O流讀取數(shù)據(jù)不完整的問題解決

    Java中I/O流讀取數(shù)據(jù)不完整的問題解決

    本文主要介紹了ava中I/O流讀取數(shù)據(jù)不完整的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java Swagger使用教程

    Java Swagger使用教程

    Swagger是一個規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化 Restful 風(fēng)格的 Web 服務(wù)。總體目標(biāo)是使客戶端和文件系統(tǒng)作為服務(wù)器以同樣的速度來更新。文件的方法、參數(shù)和模型緊密集成到服務(wù)器端的代碼,允許API來始終保持同步
    2022-07-07
  • spring?boot?Slf4j日志框架的體系結(jié)構(gòu)詳解

    spring?boot?Slf4j日志框架的體系結(jié)構(gòu)詳解

    在項目開發(fā)中記錄日志是必做的一件事情,springboot內(nèi)置了slf4j日志框架,下面這篇文章主要給大家介紹了關(guān)于spring?boot?Slf4j日志框架的體系結(jié)構(gòu),需要的朋友可以參考下
    2022-05-05
  • SpringBoot中的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則詳解

    SpringBoot中的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則詳解

    這篇文章主要介紹了SpringBoot的static靜態(tài)資源訪問、參數(shù)配置、代碼自定義訪問規(guī)則,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Mysql中備份表的多種方法

    Mysql中備份表的多種方法

    本文給大家分享Mysql中備份表的四種方法,第一種方式是小表的備份,第二種是對整個數(shù)據(jù)庫的備份與恢復(fù),第三種是對某個數(shù)據(jù)表進(jìn)行備份,每種方式給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2022-11-11
  • java8 stream 由一個list轉(zhuǎn)化成另一個list案例

    java8 stream 由一個list轉(zhuǎn)化成另一個list案例

    這篇文章主要介紹了java8 stream 由一個list轉(zhuǎn)化成另一個list案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • JSON,AJAX,Maven入門基礎(chǔ)

    JSON,AJAX,Maven入門基礎(chǔ)

    這篇文章主要介紹了JSON,AJAX和Maven基礎(chǔ),如何使用AJAX讀取Json數(shù)組里面的數(shù)據(jù),感興趣的小伙伴們可以參考一下,希望能夠幫助到你
    2021-07-07
  • Mybatis?SqlSession案例詳解

    Mybatis?SqlSession案例詳解

    這篇文章主要介紹了Mybatis?SqlSession詳解,本文我們講了如何創(chuàng)建SqlSession的幾個步驟,最后我們獲得一個DefaultSqlSession對象,里面包含了執(zhí)行器Executor和配置對象Configuration,需要的朋友可以參考下
    2023-04-04
  • java實現(xiàn)操作系統(tǒng)的短進(jìn)程作業(yè)調(diào)度示例分享

    java實現(xiàn)操作系統(tǒng)的短進(jìn)程作業(yè)調(diào)度示例分享

    java編寫的實現(xiàn)了操作系統(tǒng)中的短作業(yè)進(jìn)程,可以實現(xiàn)幾道作業(yè)同時作業(yè)調(diào)度
    2014-02-02
  • Java把多個對象的list的數(shù)據(jù)合并的方法示例

    Java把多個對象的list的數(shù)據(jù)合并的方法示例

    在Java中合并多個List可以使用遍歷、Stream API或Apache Commons Collections,通過遍歷各個List并將元素添加到新List實現(xiàn)合并,Java 8提供了Stream API,使用Stream.of()和flatMap()可以簡潔地合并List,文中給出了多種方法示例,需要的朋友可以參考下
    2024-09-09

最新評論

阿荣旗| 博湖县| 涞源县| 南和县| 塔城市| 米林县| 靖安县| 东丰县| 神农架林区| 玉树县| 宁乡县| 盈江县| 福鼎市| 昌宁县| 沙湾县| 西宁市| 松阳县| 新乡市| 五华县| 吉木萨尔县| 高邑县| 厦门市| 思南县| 临高县| 乃东县| 大厂| 斗六市| 时尚| 南开区| 鄂伦春自治旗| 白朗县| 元氏县| 乌兰县| 克拉玛依市| 西贡区| 双桥区| 漳平市| 义乌市| 同心县| 特克斯县| 阿瓦提县|