MyBatis-Plus的一些高級乾貨

MyBatis-Plus的一些高級乾貨

MyBatis Plus(簡稱 MP)是一個 MyBatis 的增強版,在 MyBatis 的基礎上只做增強不做改變,爲簡化開發、提高效率而生。

記住:MyBatis\color{red}{對MyBatis 只做增強不做改變,引入它不會對現有工程產生影響}

mp官方文檔:https://mp.baomidou.com/guide/

1.MyBatis-Plus與MyBatis的區別

  1. 對於實體類而言,需要加一定的註解。
  2. MyBatis-Plus通過@TableName\color{blue}{@TableName}讓實體類名與表名關聯,@TableField\color{blue}{@TableField}與表字段關聯。
  3. 通用性不同,MyBatis是外國人開發的,國內外皆通用,而MyBatis-Plus是由國內人士自發組織的開源,目前主要通用於國內;
  4. MyBatisPlusibatismybatis\color{green}{MyBatisPlus屬於第三方擴展,學習一般都是學習基礎,比如ibatis或者mybatis}\color{green}{而擴展是第三方提供的更高級面向開放的支持,這兩者不能作爲比較。}

注意:mybatis-plus會自動維護mybatis以及mybatis-spring的依賴,所以不需要引入後兩者,避免發生版本衝突. 只需把mybatis的依賴換成mybatis-plus的依賴。

2.全局唯一id的生成

Mybatis plus 在調用插入方法時,會自動生成id,是一個全局唯一id,一起插入到數據表中。

mp默認新增的時候,產生的是全局唯一id,採用雪花算法生成,自3.3.0開始,默認使用雪花算法+UUID。(Twitter的snowflake算法又名雪花算法,生成long類型的唯一數字)

如圖:

在這裏插入圖片描述
而這個唯一id的生成,常常用來做我們的數據庫字段的主鍵~!

3.主鍵生成策略:

在日常開發中,對於一些數據庫中的主鍵,我們一般會採用 idUUIDrediszookeeper\color{#4285f4}{自增id,}\color{#ea4335}{UUID,}\color{#fbbc05}{雪花算法,}\color{#4285f4}{redis生成,}\color{#34a853}{zookeeper生成}\color{#ea4335}{} 等方式,

具體對比:分佈式系統唯一ID生成方案

mp自3.3.0開始,默認使用雪花算法+UUID(不含中劃線)。
主鍵生成策略必須使用INPUT。

設置生成的主鍵是自增樣式:

(在mp生成id時,根據上一個id的數值,而自增)

實現過程:

3.1實體類上添加註解:

@TableId(type = IdType.INPUT) 
private Long id;

如圖:
在這裏插入圖片描述

3.2數據庫字段設置爲自增

在這裏插入圖片描述

結果:
在這裏插入圖片描述

Mp中其他的id屬性的解釋:
在這裏插入圖片描述
一旦手動輸入id之後,就需要自己配置id生成方法了!不然就可以用這些註解來生成id自動填入數據庫。

4.自動填充:

開發中,一般數據庫總有一些字段我們想要的是\color{red}{不需要修改,自動生成的}。比如創建時間,修改時間等字段!這些個操作一般都是自動化完成的,企業級都不希望手動更新。

(在阿里巴巴開發手冊中就有寫:所有的數據庫表gmt_create,gmt_modified 字段幾乎都要有,而自動化填入,便於追蹤)

實現方式

4.1 方式一:數據庫級別 (工作中不建議)

  1. 比如在表中新增字段create_time, update_time。只需要設置默認的填充方式即可。
    在這裏插入圖片描述

結果:
在這裏插入圖片描述

4.2 方法二:代碼級別 (推薦)

  1. 刪除數據庫的該字段的默認值,更新操作等設置(上一種方式我設置了,我恢復一下而已)。
    (恢復如圖下這樣)
    在這裏插入圖片描述

  2. 添加註解
    實體類上加個註解,一個是新增,一個是更新。

    // 設置填充字段的填充類型
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
  3. 編寫處理器來處理這個註解,自定義實現類來實現implements MetaObjectHandler()

    配置類源碼如下:

    @Slf4j
    @Component   // 一定不要忘記把處理器加入到IOC容器中。
    public class MyMetaObjectHandler implements MetaObjectHandler {
    
    // 插入時候的填充策略
    	@Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); //版本 3.3.0(推薦使用)
                       }
    // 更新時間的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("start update fill ....");
            this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用)
    	}
    }
    

程序會通過反射去讀取實體類中對應的註解,填入內容。

注意事項:
• 字段必須聲明TableField註解,屬性fill選擇對應策略,該聲明告知MybatisPlus需要預留注入SQL字段。
• 填充處理器MyMetaObjectHandler在SpringBoot中需要聲明@Component註解或@Bean注入。

填充失效問題解決
把date 改爲了LocalDateTime 類型,依然對應的是SQL中的datetiem或date類型。

結果:

  @Test
    public void testInsert(){
        User user =new User();
        user.setAge(23);
        int result = userMapper.insert(user); //自動生成id
        System.out.println(result);
    }

當執行插入或者更新操作時候,自動修改值。
在這裏插入圖片描述

5. 樂觀鎖:

\color{red}{樂觀鎖:}顧名思義十分樂觀,它總是認爲程序不會出現問題,無論幹什麼都不去上鎖!如果出了問題,就在測試加鎖處理,再次更新值測試。

\color{red}{悲觀鎖:}顧名思義十分悲觀,它總是認爲程序會出現問題,無論幹什麼都去上鎖!再去操作。

樂觀鎖原理機制:Versionnewversion\color{blue}{有一個Version字段 ,每次會new version ,每次操作都帶有一個版本號,來相互驗證。}

樂觀鎖實現方式:

  • 後端取記錄數據時,先查詢獲取當前version版本。
  • 更新時,帶上這個version
  • 執行更新時,set version = newVersion where version = oldVersion
  • 如果version不對,就不允許更新,失敗操作。

主要適用場景:當要更新一條記錄的時候,希望這條記錄沒有被別人更新。

5.1實現過程:

  1. 在數據庫表中添加版本字段,version int ,設置默認值1.
    在這裏插入圖片描述

  2. 實體類添加版本註解:

    @Version  //樂觀鎖註解
    private Integer version;
    

註解 @Version 必須有!

  1. 自定義一個配置類mpConfig:
    標識爲mybatis配置類,註冊樂觀鎖插件即可,

    源碼如下:

    package com.zout.mapper;
    /**
     * @Description:
     * @Author: Zoutao
     * @Date: 2020/5/16
     */
    
    import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @EnableTransactionManagement
    @Configuration  //標示爲mybatis配置類
    public class mpConfig {
        // 註冊樂觀鎖插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    

如圖:

在這裏插入圖片描述

  1. 測試方法:
    // 測試樂觀鎖 >>單線程時,方法可行
    @Test
    public void testInterceptor(){
        // 1.查詢用戶信息
        User user = userMapper.selectById(4L); 
        // 2.修改用戶信息
        user.setName("王五");
        user.setAge(500);
        user.setEmail("[email protected]");
        // 3. 執行更新操作
        int result = userMapper.updateById(user); 
        System.out.println(result);
    }

過程剖析:
首先查詢version=1,然後更新以後,version=2了。

單線程下:
在這裏插入圖片描述

對應SQL原理

update user set name = '王五',version = 2 where id = 100 and version = 1

結果,版本正常,更新成功。

多線程下:

    // 測試樂觀鎖 >> 多線程下,發現方法不可行
    @Test
    public void testInterceptor2(){
        // 模擬線程1
        User user1 = userMapper.selectById(4L);
        user1.setName("陳二");
        user1.setAge(500);
        // 模擬線程2,執行插隊操作。跟線程1互相搶奪
        User user2 = userMapper.selectById(4L);
        user2.setName("王二麻子");
        user2.setAge(800);
        userMapper.updateById(user2); // 模擬線程2搶先操作
        // 執行更新操作
        userMapper.updateById(user1); //如果沒有樂觀鎖,就會覆蓋插隊線程2的值。有樂觀鎖,則更新失敗。
    }

發現兩個線程都拿到了版本2,加鎖。

在這裏插入圖片描述

最後,因爲我們有樂觀鎖存在,所以線程2的更新操作成功了,而線程1的更新則失敗了,被限制。

在這裏插入圖片描述
可以嘗試自旋鎖來嘗試多次提交,依然可以避免同時被改寫的問題。

6. 邏輯刪除

  • 物理刪除:從數據庫直接刪除數據。
  • \color{green}{邏輯刪除}:在數據庫中沒有直接刪除,而是通過一個變量讓它失效,依舊保存在數據庫中,只是不顯示了。

應用場景:

  • 管理員可以查看被刪除的記錄,普通用戶刪除後,數據消失!這樣做是防止數據的丟失,類似於回收站功能。

6.1實現過程:

  1. 比如在數據庫表中新增一個字段 deleted。
    在這裏插入圖片描述
    當(deleted=0 >> deleted=1 )時,表示該數據被刪除了。

  2. 實體類字段上加上@TableLogic註解

    @TableLogic
    private Integer deleted;
    

說明:
• 字段支持所有數據類型(推薦使用 Integer,Boolean,LocalDateTime)
• 如果使用LocalDateTime,建議邏輯未刪除值設置爲字符串null,邏輯刪除值只支持數據庫函數例如now()

  1. 全局配置-全局邏輯刪除(非必須)
    mp,3.1.1版本以上使用,0未刪除,1已刪除。

    #全局邏輯刪除字段值
    mybatis-plus.global-config.db-config.logic-delete-field: flag
    # 邏輯已刪除值(默認爲 1)
    mybatis-plus.global-config.db-config.logic-delete-value: 1
    # 邏輯未刪除值(默認爲 0)
    mybatis-plus.global-config.db-config.logic-not-delete-value: 0
    

如圖:
在這裏插入圖片描述
注意:

使用此配置則不需要在實體類上添加 @TableLogic。
但如果實體類上有 @TableLogic 則以實體上的爲準,忽略這個全局配置。( 即先查找註解再查找全局,都沒有則此表沒有邏輯刪除。)

  1. 測試方法:
    //刪除-邏輯刪除
    @Test
    public void testDelById(){
        userMapper.deleteById(5L);
    }

原理:>>>調\color{blue}{邏輯刪除 >>>調用的是刪除方法,但實際執行的是一個更新操作。 }
在這裏插入圖片描述

效果:

在這裏插入圖片描述

使用mp自帶方法刪除和查找都會附帶邏輯刪除功能 (自己寫的xml不會)
刪除:update user set deleted=1 where id =1 and deleted=0
查找:select * from user where deleted=0

再查詢數據時:會自動加入邏輯未刪除的標誌語句來查。(自己寫的SQL則加上這個條件即可。)
如圖:
在這裏插入圖片描述
記錄依舊存在數據庫,但是值已經改變了,所以普通用戶查尋不到,admin可以。

7. 性能分析-執行 SQL 分析打印

在平時的開發中,會遇到一些慢SQL,一般是進行測試,druid監控等來找誰慢。MP提供自有插件來分析慢SQL ,如果超過設定時間,就停止運行。

(該插件 MP3.2.0 以上版本移除推薦使用第三方擴展p6spy ,執行SQL分析打印功能)

該功能依賴 p6spy 組件,完美的輸出打印 SQL 及執行時長 ,MP 3.1.0 以上版本使用。

p6spy 依賴引入:

<!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.8.7</version>
</dependency>

作用:用於輸出每條 SQL 語句及其執行時間。

效果:SQL會格式化,且出現執行時間,如果超過指定時間,會提醒報錯,自己修改優化SQL即可。

在這裏插入圖片描述

注意:該插件有性能損耗,不建議生產環境使用,在springboot配置環境爲dev或者test環境下使用就好了。


以上爲使用 mybatis Plus 框架時的一些開發記錄,也適用於以後的項目當中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章