首頁 > 軟體

Mybatis-Plus進階分頁與樂觀鎖外掛及通用列舉和多資料來源詳解

2022-03-21 19:01:19

分頁外掛

  MP中自帶了分頁外掛的功能,只需要在設定類中進行簡單的設定即可使用分頁的相關功能。分頁外掛常常與前端的分頁顯示功能相關,為了在前端美觀的顯示查詢到的資料,通常會使用分頁外掛,將所有的資料分成許多頁一頁一頁的進行顯示,不同頁的切換使用按鈕來完成

MP的外掛設定類

@Configuration
public class MybatisPlusConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 建立一個MybatisPlus的外掛攔截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 建立分頁的外掛物件並設定資料庫型別
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 設定請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求  預設false
        paginationInnerInterceptor.setOverflow(true);
        // 設定分頁的單頁最多條數,預設 500 條,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(500L);

        // 將這個分頁外掛新增到攔截器中並返回
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

自定義方法並呼叫分頁

mapper定義方法

@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 通過年齡查詢使用者資訊並分頁返回
     * @param page 傳入一個page物件
     * @param age  年齡
     * @return 返回一個page物件
     */
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}

對映檔案編寫SQL語句

<mapper namespace="com.xiaochen.mapper.UserMapper">
    <select id="selectPageVo" resultType="com.xiaochen.domain.User">
        select id,name,age,email from user where age > #{age}
    </select>
</mapper>

測試方法呼叫自定義方法

@Autowired
UserMapper mapper;

@Test
public void testpage() {

    // 建立一個page物件,設定當前頁是第1頁,每頁包含3條記錄
    Page<User> page = new Page<>(2, 3);

    // mapper呼叫selectPage方法之後將結果返回給上面的page物件
    // 第二個引數null的話就是查詢所有的記錄,如果有查詢條件的話就傳一個wrapper物件
   mapper.selectPageVo(page, 20);

    // 當前頁的資料
    System.out.println(page.getRecords());
    // 當前是第幾頁
    System.out.println(page.getCurrent());
    // 總頁數
    System.out.println(page.getPages());
    // 每頁的記錄數
    System.out.println(page.getSize());
    // 總記錄數
    System.out.println(page.getTotal());
    // 是否有下一頁
    System.out.println(page.hasNext());
    // 是否有上一頁
    System.out.println(page.hasPrevious());
}

樂觀鎖外掛

  要想使用樂觀鎖外掛,首先要知道什麼是樂觀鎖以及樂觀鎖出現的原因。現實生活中,一個管理系統往往不僅僅只有一個管理員,以修改商品價格為例,如果有兩個管理員小李和小王商品的原價為100,老闆先是讓小李將商品的價格上調50,一段時間後讓小王將商品的價格下調20,由於小李有事耽擱,兩個人同時登入管理系統獲取到商品的價格對其分別進行修改操作。如果小李最後完成操作的話商品最終為150元,如果小王最後完成操作的話商品最終為80元,這樣的話就會造成最終的價格不是老闆想要的130。

要想使用程式碼實現上述案例的話,使用執行緒來實現的話更加真實(可以模擬兩人處理先後的不確定性),但是為了簡化操作,設定最後完成操作的是小王,也即是說最後商品的價格為80

@Test
public void happyLockTest() {
    // 小李查詢商品的價格
    Product productLi = mapper.selectById(1);
    // 小王查詢到商品的價格
    Product productWang = mapper.selectById(1);
    // +50
    productLi.setPrice(productLi.getPrice() + 50);
    mapper.updateById(productLi);
    // -20
    productWang.setPrice(productWang.getPrice() - 20);
    mapper.updateById(productWang);

    // 查詢最終的商品價格
    System.out.println("最終價格為:" + mapper.selectById(1).getPrice());
}

// 控制檯最終列印 -> 最終價格為:80

  有問題就有解決問題的方法,出現這個問題的原因就是兩個管理員同時獲取到了商品的資訊並對他進行了修改,如果可以使用鎖限制同一時間只能有一個管理員對資料進行修改操作的話,就可以避免這個問題了,這就是悲觀鎖。

  不對啊,不是說要講樂觀鎖的嘛怎麼講到了悲觀鎖了?悲觀鎖將整張表鎖住了,阻止其他人對錶進行修改操作,這樣的話對效率有很大的折損。於是樂觀鎖應運而生,樂觀鎖允許任何人任何時候對錶中資料進行修改,只不過資料表中要新增一個欄位表示資料的當前版本號,資料每經過一次更新版本號就相應加一,資料每次更新的時候都會帶上版本號欄位作為更新的條件。這樣的話就可以避免之前的問題了,兩人同時獲取到的版本都是0,小李修改之後就會將版本欄位值加一也就是1,這時小王修改的時候就會查不到表中版本號為0的資料而無法修改。

  這樣的話就會避免修改衝突,但是還是無法得到想要的結果,於是可以對兩人的修改結果進行判斷,如果更新操作的返回結果不是0的話就說明更新成功,否則就再次獲取資料表中的資訊(這次就是為了獲得最新的版本號)再次進行更新操作

  使用MP中的樂觀鎖外掛,首先需要在設定類中將樂觀鎖外掛新增到攔截器中,然後再在實體類中的版本號欄位上使用@Version標誌,然後就是和平常一樣的運算元據庫即可,執行更新操作的時候會自動將當前查詢到的版本號當做條件拼接到SQL語句中

// 將樂觀鎖外掛新增到攔截器中
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

// 實體類標註版本號
@Version
private Integer version;

// 測試方法,測試兩個人最後的修改結果
@Test
public void happyLockTest() {
    // 小李查詢商品的價格
    Product productLi = mapper.selectById(1);
    // 小王查詢到商品的價格
    Product productWang = mapper.selectById(1);
    // +50
    int result = 0;
    do {
        // 更新失敗,重新查詢並修改
        productLi = mapper.selectById(1);
        productLi.setPrice(productLi.getPrice() + 50);
        result = mapper.updateById(productLi);
    } while (result == 0);
    // -20
    do {
        // 更新失敗,重新查詢並修改
        productWang = mapper.selectById(1);
        productWang.setPrice(productWang.getPrice() - 20);
        result = mapper.updateById(productWang);
    } while (result == 0);
    // 查詢最終的商品價格
    System.out.println("最終價格為:" + mapper.selectById(1).getPrice());
}

// 控制檯最終列印 -> 最終價格為:130

通用列舉類

  對於表中擁有固定幾個值的一些欄位,可以使用列舉類將比較簡單的數位或字元存入到資料庫表中,然後將這個簡單的數位或字元對應著其具體的字串表示,比如性別0代表女1代表男。這樣就會減輕資料庫的儲存壓力,提高使用者的使用體驗。 使用MP的通用列舉必須先建立一個列舉類,向外提供屬性的getter方法和全參構造器,並使用@EnumValue註解將標識的屬性值在資料庫中儲存

@Getter
@AllArgsConstructor
public enum SexEnum {

    FEMALE(0, "女"),
    MALE(1, "男");

    // 將註解標識的屬性值儲存到資料庫中
    @EnumValue
    private Integer sex;
    private String sexName;
}

  然後實體類中修改欄位對應屬性的型別為列舉型別,然後重寫toString方法,方便查詢結果顯示為資料表中數位或字元對應的具體的字串表示

// 修改欄位對應屬性的型別為列舉型別
private SexEnum sex;

// 重寫toString方法
@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + ''' +
            ", sex=" + sex.getSexName() +
            ", age=" + age +
            ", email='" + email + ''' +
            ", isDeleted=" + isDeleted +
            '}';
}

  最後在組態檔中設定通用列舉的包,也就是相當於讓你寫的列舉類生效

mybatis-plus:
  # 設定通用列舉的包
  type-enums-package: com.xiaochen.enums

測試

@Test
public void enumTest() {
    
    User user = new User();
    user.setName("張三");
    user.setAge(23);
    user.setSex(SexEnum.FEMALE);
    mapper.insert(user);

    User user1 = mapper.selectById(6);
    System.out.println(user1);
}

測試結果

多資料來源

  多資料來源就是在一個程式中同時設定多個資料庫作為資料來源進行操作,適用於多種場景:純粹多庫、 讀寫分離、 一主多從、 混合模式等。目前我們就來模擬一個純粹多庫的一個場景,設定兩個資料庫的兩張表,通過一個測試用例分別獲取兩張表的資料,如果獲取到說明多庫模擬成功

第一步: 匯入依賴

<!--mybatis-的場景啟動器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

第二步: 組態檔設定多資料來源

spring:
# 設定資料來源資訊
datasource:
dynamic:
# 設定預設的資料來源或者資料來源組,當設定的資料來源都找不到時使用預設資料來源,預設值即為master
primary: master
# 嚴格匹配資料來源,預設false.true未匹配到指定資料來源時拋異常,false匹配不到指定資料來源時使用預設資料來源
strict: false
datasource:
# 主資料來源
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus
username: root
password: 123456
# 從資料來源
slave_1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456

第三步: 照常使用方法測試在兩個資料庫查詢兩張表,唯一不同的就是在service的實現類上使用@DS註解,標註service實現類的所有方法都是對指定資料來源進行操作的

測試類及結果

到此這篇關於Mybatis-Plus進階分頁與樂觀鎖外掛及通用列舉和多資料來源詳解的文章就介紹到這了,更多相關Mybatis-Plus 分頁外掛內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


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