1. 程式人生 > 程式設計 >springboot2.3 整合mybatis-plus 高階功能及用法詳解

springboot2.3 整合mybatis-plus 高階功能及用法詳解

學習並使用mybatis-plus的一些高階功能的用法例如: AR模式、 樂觀鎖 、邏輯刪除 、自動填充、資料保護等功能

為了方便演示,咱們還是新建一個全新的專案

image-20200806214645476

引入mp依賴

 <dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.3.2</version>
 </dependency>

yml配置

# 配置埠
server:
 port: 8080
spring:
 # 配置資料來源
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
 username: root
 password: root

# mybatis-plus相關配置
mybatis-plus:
 # 以下配置均有預設值,可以不設定
 global-config:
 db-config:
  #主鍵型別 auto:"資料庫ID自增"
  id-type: auto
 configuration:
 # 是否開啟自動駝峰命名規則對映:從資料庫列名到Java屬性駝峰命名的類似對映
 map-underscore-to-camel-case: true
 # 如果查詢結果中包含空值的列,則 MyBatis 在對映的時候,不會對映這個欄位
 call-setters-on-nulls: true
 # 這個配置會將執行的sql打印出來,在開發或測試的時候可以用
 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

在 Spring Boot 啟動類中新增 @MapperScan 註解,掃描 Mapper 資料夾

image-20200806215534085

(一)AR模式使用

ActiveRecord模式:支援 ActiveRecord 形式呼叫,實體類只需繼承 Model 類即可進行強大的 CRUD 操作

即直接使用實體類 CRUD操作

1.繼承Model

image-20200806221012349

點進Model 類中 ,發現其提供了一些基礎的CRUD操作方法,並實現了序列化介面

image-20200806220842130

注意的是,如果要使用ActiveRecord模式,僅僅繼承Model 是不行的,這一點官網沒有很顯示的提到,還需要編寫mapper介面 繼承BaseMapper介面,泛型為當前實體類

2.mapper介面

如果不編寫Mapper直接使用Model方法會報錯:

image-20200806221302376

那麼,咱們來編寫mapper

image-20200806221326120

再次測試

3.CRUD操作

新增操作

image-20200806221413677

查詢操作

image-20200806221705933

修改操作

image-20200806221825358

刪除操作

image-20200806221936204

此AR模式呢,可以在開發中減少我們很多的呼叫程式碼,簡單操作無需額外使用Mapper、service呼叫

(二)樂觀鎖

使用Mybatis-plus實現樂觀鎖

樂觀鎖:總是假設最好的情況,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量。

mybatis-plus 提供的樂觀鎖 是採用了版本號機制

資料表中加上一個資料版本號version欄位,表示資料被修改的次數,當資料被修改時,version值會加一。當執行緒A要更新資料值時,在讀取資料的同時也會讀取version值,在提交更新時,若剛才讀取到的version值為當前資料庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

mp專案使用樂觀鎖是使用其外掛配置–配置Bean的形式

1.bean配置

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
 return new OptimisticLockerInterceptor();
}

image-20200806222513767

2.實體類以及資料庫新增對應欄位以及列

@Version
private Integer version;

image-20200806222639173

image-20200806222908272

至於version初始值,可以資料庫預設設定為0,也可以再新增資料時手動設定verion版本號,個人是採用了資料庫預設值

那麼我們在做任何查詢修改刪除的時候呢,mp會預設幫我們吧版本號作為條件帶上,判斷與資料庫中該資料版本號是否一致。

3.相關操作以及注意事項

首先插入一條資料

image-20200806223134584

image-20200806223150227

查詢並修改該條資訊

發現其在修改的時候,將version作為了條件,並對version做了修改 set操作(預設是在原基礎上+1)

image-20200806224245623

image-20200806224258714

需要注意的幾個點:

支援的資料型別只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整數型別下 newVersion = oldVersion + 1
newVersion 會回寫到 entity 中
僅支援 updateById(id) 與 update(entity,wrapper) 方法
在 update(entity,wrapper) 方法下,wrapper 不能複用!!!

什麼意思呢,就是要想使用樂觀說,首先 型別有限制,其次,修改方法僅僅只有上方兩個有效,才會在修改時候對版本號就行修改操作 以及 要想版本號升級必須 是要把之前版本號傳過去。

即version操作時,我必須把舊的帶過去

版本號不對,是無法進行資料更新操作的(刪除、修改)

image-20200806224911876

而如果不傳遞版本號的話,那麼該欄位就不會被維護了(失去了樂觀鎖 版本號機制 的意義了)

image-20200806225056838

版本號回傳 修改正確 版本號維護成功

image-20200806225332135

如此,就實現了樂觀鎖了,mp基礎上使用樂觀鎖,就是這麼簡單

(三)邏輯刪除

物理刪除:將資料庫中該資訊進行徹底刪除,無法恢復。 應的SQL語句:delete from 表名 where 條件

邏輯刪除:邏輯刪除的本質是修改操作,所謂的邏輯刪除其實並不是真正的刪除,而是在表中將對應的是否刪除標識,然後修改 查詢操作時將 是否刪除標識欄位作為條件帶上,進而達到邏輯上刪除了資料,但實際仍然保留了資料(儘管此資料在邏輯中不會再使用了)

例如:自己設定一個邏輯刪除欄位,例如1表示資料有效,0表示被刪除即可,預設是1

Mybatis-plus 已經為我們提供了邏輯刪除封裝

只對自動注入的sql起效:

插入: 不作限制
查詢: 追加where條件過濾掉已刪除資料,且使用 wrapper.entity 生成的where條件會忽略該欄位
更新: 追加where條件防止更新到已刪除資料,且使用 wrapper.entity 生成的where條件會忽略該欄位
刪除: 轉變為 更新
例如:

刪除: update user set deleted=1 where id = 1 and deleted=0
查詢: select id,name,deleted from user where deleted=0
欄位型別支援說明:

支援所有資料型別(推薦使用 Integer,Boolean,LocalDateTime)
如果資料庫欄位使用datetime,邏輯未刪除值和已刪除值支援配置為字串null,另一個值支援配置為函式來獲取值如now()
附錄:

邏輯刪除是為了方便資料恢復和保護資料本身價值等等的一種方案,但實際就是刪除。
如果你需要頻繁查出來看就不應使用邏輯刪除,而是以一個狀態去表示。

使用步驟:

1.資料庫新增欄位

對某個表的資料需要使用邏輯刪除,則必須建立邏輯刪除欄位

image-20200808110331856

2.mp邏輯刪除配置

在原有的mp配置上 新增邏輯刪除設定

其已刪除 未刪除值均有預設值 1 0 如果你預想設定值與之一致,僅僅編寫 邏輯刪除欄位名即可

image-20200808110905817

3.實體類加邏輯刪除欄位以及註解

image-20200808111149966

mp中 邏輯刪除相關配置就沒了 ,很是簡單------------咱們開始測試

咱們先刪除資料庫中原有資料

image-20200808111441145

可以看到 ,刪除語句實際上是執行了update(修改) 額外將 我們設定好的邏輯刪除欄位值作為條件(未刪除 0),並修改 值為1(已刪除)

image-20200808111531657

接下來,我們來進行查詢操作,看是否還能取出資料

total=0,沒有資料, 那麼我們便做到了業務意義上的資料刪除(邏輯刪除)

image-20200808111933875

其只要是設定了邏輯刪除 ,修改 刪除 查詢操作均會攜帶上未刪除條件 ,保證操作的資料時 “存在” 的()

(四)自動填充

在開發中哈,我們一個表的欄位除了業務欄位外,實際上還會新增維護欄位 ,即 建立人 建立時間 修改人 修改時間 ,讓資料的操作 有跡可循,方便管理

如下:

image-20200808112656976

實體類新增維護欄位資訊

image-20200808112809346

那麼每次在操作資料的時候需要我們手動插入到該model中 進行儲存,再操作資料

例如新增時

image-20200808113226978

image-20200808113243561

例如修改時

image-20200808113539478

image-20200808113559081

這樣呢,每次我們在操作資料時都需要在業務程式碼中編寫 新增使用者ID 當前時間 修改使用者ID 修改時間等欄位等,就比較繁瑣

專案很大,幾百個Model 乘以Four 那麼就額外編寫幾千行程式碼進行維護了

解決辦法:

1.自定義Aop 進行資料填充

2.使用現成的 (mp都用了,用他的自動填充不香嗎)

操作開始:

1.自定義實現類 MyMetaObjectHandler

這裡需要注意哈

這二者呢,一個是插入的型別 一個是插入的值 必須對應上,或者 自動填充時會報錯

image-20200808114936751

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

 @Override
 public void insertFill(MetaObject metaObject) {
  log.info("start insert fill ....");
  this.strictInsertFill(metaObject,"createTime",Long.class,System.currentTimeMillis());
  //開發中 建立者 修改者ID 通過Aop 或者許可權框架獲取當前操作使用者 ,用使用者ID進行填充即可
  this.strictInsertFill(metaObject,"createId",666L);

 }

 @Override
 public void updateFill(MetaObject metaObject) {
  log.info("start update fill ....");
  this.strictUpdateFill(metaObject,"modifyTime",System.currentTimeMillis());
  this.strictUpdateFill(metaObject,"modifyId",666L);

 }
}

2.實體類註解

要開啟自動填充功能 實現 MetaObjectHandler 還不行,因為Mp 啊,對其欄位預設是不做處理的,所以,咱們配置了 新增修改 自動填充時 還需要在其欄位上進行開啟

@TableField(fill = FieldFill.INSERT)

image-20200808114731349

image-20200808114705528

OK。設定好了,咱們插入修改試一試吧!

image-20200808115231603

image-20200808115251910修改

image-20200808115517443

image-20200808115528774

如此 mp的自動填充就可以了,根據業務 合理對默寫欄位填充,填充什麼值 自己考量即可

但是呢,也是有一定問題的

比如:我有一個定時維護功能,是由xxl-job發起的定時任務,那麼這個時候,我欄位維護資訊,為了區分開到底是認為維護還是自動維護,那麼就需要手動設定 建立修改人 以及時間了

這個時候呢,自動填充功能會把我們自己設定的進行覆蓋

所以呢,自動填充咱們也可以進行優化,當有該維護欄位時,且欄位無值時才填充,當無維護欄位或者 維護欄位設定了值則不填充

3.自動填充優化

實際就是做了判斷 判斷該欄位是否有set屬性 有則嘗試填充 (無值則填充)

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

 @Override
 public void insertFill(MetaObject metaObject) {
  //判斷是否有set屬性
  if (metaObject.hasSetter("createId")) {
   //判斷是否有值 如果沒設定值 則為null
   Object createId = getFieldValByName("createId",metaObject);
   if (createId == null) {
    log.info("建立人需要維護 且值為空 需要填充 ");
    //開發中 建立者 修改者ID 通過Aop 或者許可權框架獲取當前操作使用者 ,用使用者ID進行填充即可
    this.strictInsertFill(metaObject,666L);

   }
  }
  if (metaObject.hasSetter("createTime")) {
   Object createTime = getFieldValByName("createTime",metaObject);
   if (createTime == null) {
    log.info("建立時間需要維護 且值為空 需要填充 ");
    this.strictInsertFill(metaObject,System.currentTimeMillis());
   }
  }

 }

 @Override
 public void updateFill(MetaObject metaObject) {
  if (metaObject.hasSetter("modifyId")) {
   Object modifyId = getFieldValByName("modifyId",metaObject);
   if (modifyId == null) {
    log.info("修改人需要維護 且值為空 需要填充 ");
    this.strictUpdateFill(metaObject,666L);
   }
  }
  if (metaObject.hasSetter("modifyTime")) {
   Object modifyTime = getFieldValByName("modifyTime",metaObject);
   if (modifyTime == null) {
    log.info("修改時間需要維護 且值為空 需要填充 ");
    this.strictUpdateFill(metaObject,System.currentTimeMillis());
   }
  }

 }
}

測試:

我這裡設定了建立者ID,雖然createId需要維護,但我們設定了值 則不會進行填充了,修改亦是如此!

image-20200808124200342

image-20200808124331978

那麼自動填充功能,就完了,整合時 結合專案,適當修改即可。

(五)資料保護

使用mp中的加密方式,對配置檔案中一些敏感資訊進行加密(例如密碼)

其和 Jasypt 專案加密方式類似

1.生成隨機祕鑰以及內容加密

image-20200808154301136

image-20200808154406180

2.配置檔案替換

我們將原本的明文資訊(root)換成加密後的密文資訊

格式:

mpw:xxxx密文資訊

image-20200808154539290

3.設定金鑰到啟動引數中

idea 設定方式:

image-20200808154642114

image-20200808154702402

啟動測試–獲取到了資料 證明資料庫連線成功,其加密內容在連線時也被金鑰解密了,但配置中,無明文資訊,一定程度保護了專案

image-20200808154741030

jar 啟動時 設定金鑰引數:

image-20200808155350475

專案地址:springboot-mp進階

到此這篇關於springboot2.3 整合mybatis-plus 高階功能及用法詳解的文章就介紹到這了,更多相關springboot2.3 整合mybatis-plus內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!