一、關於Mybatis-Plus外掛
1.1 簡介
Mybatis-Plus 提供了豐富的外掛機制,這些外掛可以幫助開發者更方便地擴充套件 Mybatis 的功能,提升開發效率、最佳化效能和實現一些常用的功能。
1.2 實現原理
Mybatis-Plus 的外掛實現是基於 MyBatis 的攔截器機制, 這些外掛透過 MybatisPlusInterceptor
來實現對 MyBatis 執行過程的攔截和增強。
MyBatis 外掛本質上是對 SQL 執行過程的攔截和擴充套件,Mybatis-Plus 外掛透過在 MyBatis 的執行生命週期中插入攔截器來實現一些增強功能。透過這種方式,Mybatis-Plus 可以實現分頁、效能分析、樂觀鎖等功能的自動化處理。
MybatisPlusInterceptor 概覽
MybatisPlusInterceptor
是 MyBatis-Plus 的核心外掛,它代理了 MyBatis 的 Executor#query
、Executor#update
和 StatementHandler#prepare
方法,允許在這些方法執行前後插入自定義邏輯。
屬性
MybatisPlusInterceptor
有一個關鍵屬性 interceptors
,它是一個 List<InnerInterceptor>
型別的集合,用於儲存所有要應用的內部攔截器。
InnerInterceptor 介面
所有 MyBatis-Plus 提供的外掛都實現了 InnerInterceptor
介面,這個介面定義了外掛的基本行為。目前,MyBatis-Plus 提供了以下外掛:
- 自動分頁:
PaginationInnerInterceptor
- 多租戶:
TenantLineInnerInterceptor
- 動態表名:
DynamicTableNameInnerInterceptor
- 樂觀鎖:
OptimisticLockerInnerInterceptor
- SQL 效能規範:
IllegalSQLInnerInterceptor
- 防止全表更新與刪除:
BlockAttackInnerInterceptor
1.3 配置方式
外掛的配置可以在 Spring 配置中進行,也可以在 Spring Boot 專案中透過 Java 配置來新增。以下是兩種配置方式的示例:
- Spring 配置:在 Spring 配置中,需要建立
MybatisPlusInterceptor
的例項,並將它新增到 MyBatis 的外掛列表中。 - Spring Boot 配置:在 Spring Boot 專案中,可以透過 Java 配置來新增外掛,例如新增分頁外掛。
Spring Boot 配置示例
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新增分頁外掛
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
配置多個外掛
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 新增分頁外掛
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 新增效能分析外掛
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1000); // 設定SQL最大執行時間,單位為毫秒
interceptor.addInnerInterceptor(performanceInterceptor);
// 新增防全表更新與刪除外掛
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
注意
使用多個外掛時,需要注意它們的順序。建議的順序是:
- 多租戶、動態表名
- 分頁、樂觀鎖
- SQL 效能規範、防止全表更新與刪除
總結:對 SQL 進行單次改造的外掛應優先放入,不對 SQL 進行改造的外掛最後放入。
二、分頁外掛(PaginationInnerInterceptor
)
2.1 關於
簡介
MyBatis-Plus 的分頁外掛 PaginationInnerInterceptor
提供了強大的分頁功能,支援多種資料庫,使得分頁查詢變得簡單高效。用時只需要在查詢方法中傳入Page<T>
物件,外掛會自動處理分頁相關的SQL構建和結果集解析。
主要功能
-
自動分頁:
- 透過在查詢時自動新增
LIMIT
和OFFSET
等 SQL 關鍵字,來實現分頁功能。
- 透過在查詢時自動新增
-
相容性:
- 支援多種資料庫的分頁語法,確保在不同資料庫上都能正常工作。
-
動態引數:
- 可以動態地根據使用者的請求引數(如頁碼和每頁大小)生成分頁資訊,而無需手動處理 SQL。
-
效能最佳化:
- 在執行分頁查詢時,透過設定合理的引數,能夠減少查詢的時間複雜度,提高查詢效率。
關鍵引數
- DbType:指定資料庫型別,影響生成的分頁 SQL 語句。例如,
DbType.MYSQL
會生成適用於 MySQL 的分頁語句。 - setOverflow:允許配置是否允許請求的頁碼超出最大頁碼範圍(例如,返回最後一頁的資料)。
- setMaxLimit:可以設定每頁最大記錄數,避免使用者請求過大的分頁資料。
2.2 使用
配置外掛
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新增分頁外掛
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多個外掛, 切記分頁最後新增
// 如果有多資料來源可以不配具體型別, 否則都建議配上具體的 DbType
return interceptor;
}
}
分頁查詢
Page<User> page = new Page<>(1, 10); // 當前頁, 每頁記錄數
IPage<User> userPage = userMapper.selectPage(page, null);
三、效能分析外掛(PerformanceInterceptor
)
3.1 關於
簡介
效能分析外掛(PerformanceInterceptor
)是 MyBatis-Plus 提供的一個非常有用的工具,它可以用來監控 SQL 語句的執行時間,幫助開發者及時發現和最佳化慢查詢問題。
3.2 使用
配置外掛
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 新增效能分析外掛
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(1000); // 設定SQL最大執行時間,單位為毫秒
interceptor.addInnerInterceptor(performanceInterceptor);
return interceptor;
}
}
配置日誌輸出
為了更好地監控 SQL 語句的執行情況,可以配置日誌輸出。在 application.properties
或 application.yml
檔案中新增日誌配置:
logging:
level:
com.baomidou.mybatisplus: DEBUG
- SQL 執行時間記錄:每次執行 SQL 語句時,外掛會記錄執行時間。
- 超時處理:如果 SQL 語句的執行時間超過
setMaxTime
方法設定的閾值(預設為 0,表示不限制),外掛會記錄一條警告日誌或丟擲異常,具體行為取決於配置。
如果 SQL 語句執行時間超過設定的閾值,日誌輸出可能如下所示:
2024-11-08 10:41:00 [http-nio-8080-exec-1] WARN c.b.mybatisplus.extension.plugins.inner.PerformanceInterceptor - [performance] SQL Execution Time: 1500 ms
透過以上步驟,你可以在 MyBatis-Plus 中輕鬆配置和使用效能分析外掛,幫助你及時發現和最佳化慢查詢問題。
四、防全表更新與刪除外掛(BlockAttackInterceptor
)
4.1 關於
簡介
MyBatis-Plus 提供了一個防全表更新與刪除外掛(BlockAttackInterceptor
),該外掛可以防止在沒有 WHERE 條件的情況下執行全表更新或刪除操作,從而避免誤操作導致的資料丟失或損壞
使用
配置外掛
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 新增防全表更新與刪除外掛
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
測試
在控制器層中呼叫 Service 層的方法進行查詢。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/delete-all")
public String deleteAllUsers() {
try {
userService.remove(null); // 嘗試刪除所有使用者
return "All users deleted successfully";
} catch (Exception e) {
return "Failed to delete all users: " + e.getMessage();
}
}
@PostMapping("/update-all")
public String updateAllUsers() {
try {
User user = new User();
user.setName("Updated Name");
userService.updateById(user); // 嘗試更新所有使用者
return "All users updated successfully";
} catch (Exception e) {
return "Failed to update all users: " + e.getMessage();
}
}
}
-
嘗試刪除所有使用者:訪問
/users/delete-all
介面。-
如果沒有 WHERE 條件,外掛會丟擲異常並阻止刪除操作。
-
控制檯輸出示例:
Failed to delete all users: Cannot execute delete operation without where condition!
-
-
嘗試更新所有使用者:訪問
/users/update-all
介面。-
如果沒有 WHERE 條件,外掛會丟擲異常並阻止更新操作。
-
控制檯輸出示例:
Failed to update all users: Cannot execute update operation without where condition!
-
五、自定義外掛
如果內建外掛不能滿足需求,可以自定義外掛。自定義外掛需要實現 Interceptor
或 InnerInterceptor
介面,並在 intercept
方法中實現自定義邏輯。
示例:
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import java.sql.Connection;
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class CustomInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 自定義邏輯
System.out.println("CustomInterceptor: Before SQL execution");
Object result = invocation.proceed();
System.out.println("CustomInterceptor: After SQL execution");
return result;
}
@Override
public Object plugin(Object target) {
return Interceptor.super.plugin(target);
}
@Override
public void setProperties(Properties properties) {
Interceptor.super.setProperties(properties);
}
}
註冊自定義外掛:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new CustomInterceptor());
return interceptor;
}
透過上述機制和介面,MyBatis-Plus 提供了靈活的外掛擴充套件能力,使開發者可以根據具體需求定製化功能。