MyBatis-Plus 全解析(從入門到實戰,覆蓋99%開發場景)
MyBatis-Plus(簡稱 MP)是 MyBatis 的增強工具,核心思想是「簡化開發、提高效率」,在 MyBatis 基礎上只做增強不做改變,支持所有 MyBatis 原生功能,同時提供了 CRUD 接口、條件構造器、代碼生成器等一系列高效特性,徹底告別重複的 XML 配置和 SQL 編寫。
本文將從「環境搭建→核心特性→進階用法→實戰案例→最佳實踐」全方位拆解 MyBatis-Plus,覆蓋從入門到生產的全場景需求。
一、MyBatis-Plus 核心優勢
先明確 MP 相比原生 MyBatis 的核心價值,理解為什麼要使用它:
- 零 XML 配置:內置 CRUD 接口,無需編寫 XML 和 Mapper 方法,直接調用即可;
- 強大的條件構造器:支持 Lambda 表達式、鏈式調用,動態 SQL 編寫無需拼接字符串;
- 代碼生成器:自動生成 Entity、Mapper、Service、Controller 全套代碼,開發效率翻倍;
- 豐富的插件支持:分頁插件、樂觀鎖插件、邏輯刪除、自動填充等,開箱即用;
- 低侵入性:完全兼容 MyBatis 原生用法,老項目可無縫遷移;
- 高性能:底層優化充分,無額外性能損耗,甚至通過緩存、SQL 優化提升效率。
二、前置環境準備(Spring Boot 集成)
MP 支持 Spring、Spring Boot、Spring Cloud 等環境,這裏以最常用的 Spring Boot 3.x + MySQL 8.x 為例,搭建基礎環境。
2.1 依賴配置(Maven)
在 pom.xml 中引入 MP 核心依賴(無需額外引入 MyBatis,MP 已內置兼容版本):
<!-- Spring Boot 父依賴(已引入可忽略) -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<dependencies>
<!-- Spring Boot Web 依賴(用於接口測試,可選) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus 核心依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version> <!-- 推薦使用最新穩定版 -->
</dependency>
<!-- MySQL 驅動(Spring Boot 3.x 需用 8.x 驅動) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- lombok(簡化實體類 getter/setter,可選但推薦) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 測試依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2.2 配置文件(application.yml)
配置數據庫連接、MyBatis-Plus 核心參數(核心配置必須正確,否則無法啓動):
spring:
# 數據庫配置
datasource:
url: jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
username: root # 你的 MySQL 用户名
password: 123456 # 你的 MySQL 密碼
driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8.x 驅動類名
mybatis-plus:
# 1. mapper.xml 文件存放路徑(若使用 XML 自定義 SQL,需配置)
mapper-locations: classpath:mapper/*.xml
# 2. 實體類包掃描(自動識別 @TableName 註解的實體)
type-aliases-package: com.example.mpdemo.entity
# 3. 全局配置
global-config:
db-config:
# 主鍵生成策略(默認雪花算法,後續詳細講)
id-type: ASSIGN_ID
# 邏輯刪除字段配置(全局統一配置,後續詳細講)
logic-delete-field: isDeleted
logic-delete-value: 1 # 已刪除
logic-not-delete-value: 0 # 未刪除
# 表名前綴(全局統一添加表前綴,如實體 User 對應表 mp_user)
table-prefix: mp_
# 4. 原生 MyBatis 配置(可選)
configuration:
# 打印 SQL(開發環境開啓,生產環境關閉)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 駝峯命名自動轉換(數據庫字段 user_name → 實體屬性 userName)
map-underscore-to-camel-case: true
# 開啓二級緩存(默認關閉,根據需求開啓)
cache-enabled: false
2.3 啓動類註解
在 Spring Boot 啓動類上添加 @MapperScan 註解,掃描 Mapper 接口所在包:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 掃描 Mapper 接口(替換為你的 Mapper 包路徑)
@MapperScan("com.example.mpdemo.mapper")
@SpringBootApplication
public class MpDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MpDemoApplication.class, args);
}
}
2.4 環境驗證
創建測試表 mp_user(對應實體 User),用於後續功能測試:
CREATE TABLE `mp_user` (
`id` bigint NOT NULL COMMENT '主鍵ID',
`user_name` varchar(50) NOT NULL COMMENT '用户名',
`age` int DEFAULT NULL COMMENT '年齡',
`email` varchar(100) DEFAULT NULL COMMENT '郵箱',
`is_deleted` tinyint DEFAULT 0 COMMENT '邏輯刪除(0-未刪,1-已刪)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
至此,MyBatis-Plus 基礎環境搭建完成,接下來進入核心特性講解。
三、核心特性:Entity 實體類註解(映射基礎)
Entity 是數據庫表的映射類,MP 通過註解關聯實體與表、字段與列,核心註解如下(必須掌握):
|
註解 |
作用 |
常用屬性 |
示例 |
|
|
關聯實體與數據庫表 |
|
|
|
|
標記主鍵字段 |
|
|
|
|
標記普通字段(非主鍵) |
|
|
|
|
標記邏輯刪除字段(優先級高於全局配置) |
|
|
|
|
標記樂觀鎖字段 |
- |
|
|
|
枚舉字段映射(數據庫存儲枚舉值) |
- |
枚舉類中 |
|
|
單獨給實體添加表前綴(覆蓋全局配置) |
|
|
3.1 實體類示例(完整規範)
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
// Lombok 註解,自動生成 getter/setter/toString 等方法
@Data
// 關聯數據庫表(若全局配置了 table-prefix,可省略 value,自動拼接前綴)
@TableName("mp_user")
public class User {
// 主鍵(雪花算法生成,適合分佈式場景)
@TableId(type = IdType.ASSIGN_ID)
private Long id;
// 普通字段(數據庫列名 user_name,駝峯自動轉換可省略 value)
@TableField(value = "user_name")
private String userName;
// 普通字段(允許為 null)
private Integer age;
// 普通字段(非數據庫字段,查詢時忽略)
@TableField(exist = false)
private String tempField;
// 邏輯刪除字段(覆蓋全局配置)
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
// 自動填充:創建時間(插入時填充)
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
// 自動填充:更新時間(插入和更新時填充)
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
3.2 主鍵生成策略(IdType)
MP 提供 7 種主鍵生成策略,根據業務場景選擇:
|
策略類型 |
説明 |
適用場景 |
|
|
數據庫自增(需數據庫表主鍵設為 AUTO_INCREMENT) |
單庫單表,無分佈式需求 |
|
|
雪花算法(Snowflake)生成 19 位 Long 型 ID |
分佈式系統,需要全局唯一 ID |
|
|
生成 UUID(去除橫線,32 位字符串) |
無需有序 ID,需要字符串主鍵 |
|
|
手動輸入主鍵 |
主鍵由業務邏輯生成(如訂單號) |
|
|
未設置策略(默認跟隨全局配置) |
- |
|
|
舊版雪花算法(已過時,推薦用 ASSIGN_ID) |
兼容舊項目 |
|
|
舊版雪花算法(字符串形式,已過時) |
兼容舊項目,字符串主鍵 |
注意:使用 AUTO 策略時,需確保數據庫表主鍵字段設置了 AUTO_INCREMENT,否則會報錯。
四、核心特性:CRUD 接口(無 SQL 開發)
MP 提供了 BaseMapper(Mapper 層)和 IService(Service 層)兩套 CRUD 接口,繼承後直接調用,無需編寫任何 SQL 和方法。
4.1 Mapper 層:BaseMapper 接口
4.1.1 用法
創建 Mapper 接口,繼承 BaseMapper<Entity>,即可獲得全套 CRUD 方法:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.springframework.stereotype.Repository;
// @Repository 註解(Spring 掃描為 DAO 組件)
@Repository
public interface UserMapper extends BaseMapper<User> {
// 無需編寫任何方法,BaseMapper 已提供全套 CRUD
}
4.1.2 BaseMapper 核心方法(常用 15+)
|
方法名 |
功能描述 |
參數説明 |
返回值 |
|
|
新增一條記錄 |
實體對象(非 null 字段會插入) |
影響行數(int) |
|
|
根據主鍵刪除 |
主鍵 ID(Long/String 等) |
影響行數(int) |
|
|
根據條件刪除(Map 鍵為列名,值為條件) |
條件 Map |
影響行數(int) |
|
|
根據條件構造器刪除 |
QueryWrapper/LambdaQueryWrapper |
影響行數(int) |
|
|
根據主鍵更新(非 null 字段才更新) |
實體對象 |
影響行數(int) |
|
|
條件更新(entity 存更新字段,wrapper 存條件) |
實體對象 + 條件構造器 |
影響行數(int) |
|
|
根據主鍵查詢 |
主鍵 ID |
實體對象(T) |
|
|
批量查詢(根據主鍵集合) |
主鍵集合(如 List) |
List |
|
|
根據條件查詢(Map 條件) |
條件 Map |
List |
|
|
根據條件構造器查詢列表 |
條件構造器(可無,查全部) |
List |
|
|
根據條件查詢單條記錄(需確保結果唯一) |
條件構造器 |
T(無結果返回 null) |
|
|
統計符合條件的記錄數 |
條件構造器 |
總數(long) |
|
|
分頁查詢 |
分頁對象 + 條件構造器 |
Page(含總條數、當前頁數據) |
4.1.3 Mapper 層調用示例(Service 層中注入使用)
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class UserService {
// 注入 Mapper(也可使用 @Autowired)
@Resource
private UserMapper userMapper;
// 1. 新增用户
public boolean addUser(User user) {
return userMapper.insert(user) > 0;
}
// 2. 根據 ID 查詢用户
public User getUserById(Long id) {
return userMapper.selectById(id);
}
// 3. 查詢所有用户
public List<User> getAllUsers() {
return userMapper.selectList(null); // queryWrapper 為 null 表示無條件
}
// 4. 根據 ID 更新用户(只更新非 null 字段)
public boolean updateUser(User user) {
return userMapper.updateById(user) > 0;
}
// 5. 根據 ID 刪除用户
public boolean deleteUser(Long id) {
return userMapper.deleteById(id) > 0;
}
}
4.2 Service 層:IService 接口(推薦)
IService 是對 BaseMapper 的進一步封裝,提供了更豐富的批量操作、鏈式調用等功能,同時規範了 Service 層的代碼結構(IService 接口 + ServiceImpl 實現類)。
4.2.1 用法步驟
- 創建 Service 接口,繼承
IService<Entity>:
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mpdemo.entity.User;
public interface UserService extends IService<User> {
// 可添加自定義業務方法(如複雜查詢、多表關聯)
List<User> getUserByAgeRange(Integer minAge, Integer maxAge);
}
- 創建 Service 實現類,繼承
ServiceImpl<Mapper, Entity>,並實現自定義接口:
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import com.example.mpdemo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 實現自定義方法(可直接使用 baseMapper 調用 Mapper 層方法)
@Override
public List<User> getUserByAgeRange(Integer minAge, Integer maxAge) {
// 這裏後續結合條件構造器實現,先佔位
return null;
}
}
4.2.2 IService 核心方法(比 BaseMapper 更強大)
|
方法名 |
功能描述 |
優勢 |
|
|
新增(同 BaseMapper.insert) |
返回 boolean,更直觀 |
|
|
批量新增(默認批次 1000) |
優化批量插入性能,無需手動循環 |
|
|
新增或更新(有主鍵則更新,無則新增) |
簡化“upsert”場景 |
|
|
批量新增或更新 |
高效處理批量 upsert |
|
|
根據主鍵刪除(同 BaseMapper.deleteById) |
返回 boolean |
|
|
批量刪除(根據主鍵集合) |
無需手動循環刪除 |
|
|
根據主鍵更新(同 BaseMapper.updateById) |
返回 boolean |
|
|
批量更新(根據主鍵) |
優化批量更新性能 |
|
|
根據主鍵查詢(同 BaseMapper.selectById) |
返回 T,命名更直觀 |
|
|
查詢所有(同 BaseMapper.selectList(null)) |
簡化無條件查詢 |
|
|
批量查詢(同 BaseMapper.selectBatchIds) |
命名更直觀 |
|
|
統計總數(同 BaseMapper.selectCount(null)) |
簡化無條件統計 |
|
|
分頁查詢(無條件) |
簡化分頁操作 |
|
|
條件分頁查詢 |
分頁 + 條件構造器無縫結合 |
4.2.3 Service 層調用示例(Controller 中使用)
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// 新增用户
@PostMapping
public boolean addUser(@RequestBody User user) {
return userService.save(user);
}
// 批量新增用户
@PostMapping("/batch")
public boolean addUserBatch(@RequestBody List<User> userList) {
return userService.saveBatch(userList);
}
// 根據 ID 查詢用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
// 分頁查詢所有用户(page:頁碼,size:每頁條數)
@GetMapping("/page")
public IPage<User> getUserPage(@RequestParam Integer page, @RequestParam Integer size) {
return userService.page(new Page<>(page, size));
}
// 根據 ID 更新用户
@PutMapping
public boolean updateUser(@RequestBody User user) {
return userService.updateById(user);
}
// 根據 ID 刪除用户
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.removeById(id);
}
}
五、核心特性:條件構造器(動態 SQL 神器)
條件構造器是 MP 最強大的功能之一,支持 鏈式調用、Lambda 表達式、複雜條件組合,無需手動拼接 SQL,徹底解決動態 SQL 編寫繁瑣、易出錯的問題。
MP 提供 4 種核心條件構造器,重點掌握前兩種:
|
構造器類型 |
説明 |
優點 |
缺點 |
|
|
非 Lambda 形式,通過字符串指定字段名 |
兼容所有場景,無需實體類字段對應 |
字段名硬編碼,易寫錯(無編譯檢查) |
|
|
Lambda 形式,通過實體類方法引用字段 |
字段名編譯檢查,無硬編碼錯誤 |
實體類字段與數據庫列必須映射正確 |
|
|
非 Lambda 形式,用於更新操作的條件構造 |
支持更新字段設置(如 set("age", 20)) |
字段名硬編碼 |
|
|
Lambda 形式,用於更新操作的條件構造 |
字段名編譯檢查,更新字段無需硬編碼 |
實體類字段與數據庫列必須映射正確 |
5.1 QueryWrapper 用法(非 Lambda)
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mpdemo.entity.User;
import java.util.List;
// 1. 條件查詢:查詢年齡 > 18 且用户名包含 "張" 的用户
public List<User> queryUser() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 鏈式調用條件:age > 18
queryWrapper.gt("age", 18)
// 用户名 like %張%
.like("user_name", "張")
// 按創建時間降序排序
.orderByDesc("create_time");
return userService.list(queryWrapper);
}
// 2. 條件統計:統計郵箱不為 null 且未刪除的用户數
public long countUser() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNotNull("email")
.eq("is_deleted", 0); // 邏輯刪除字段
return userService.count(queryWrapper);
}
5.2 LambdaQueryWrapper 用法(推薦,無硬編碼)
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.mpdemo.entity.User;
import java.util.List;
// 1. 條件查詢:年齡在 18-30 之間,且郵箱以 "@qq.com" 結尾
public List<User> queryUserByLambda() {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 字段名通過 User::getter 方法引用,編譯時檢查
lambdaQueryWrapper.between(User::getAge, 18, 30) // age between 18 and 30
.likeRight(User::getEmail, "@qq.com") // email like '@qq.com%'
.orderByAsc(User::getCreateTime); // 按創建時間升序
return userService.list(lambdaQueryWrapper);
}
// 2. 動態條件:根據傳入參數動態拼接條件(如用户名和年齡可選)
public List<User> queryUserDynamic(String userName, Integer age) {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 若 userName 不為 null 且不為空,添加模糊查詢條件
if (userName != null && !userName.isEmpty()) {
lambdaQueryWrapper.like(User::getUserName, userName);
}
// 若 age 不為 null,添加年齡 >= 條件
if (age != null) {
lambdaQueryWrapper.ge(User::getAge, age);
}
// 強制查詢未刪除的用户(邏輯刪除)
lambdaQueryWrapper.eq(User::getIsDeleted, 0);
return userService.list(lambdaQueryWrapper);
}
5.3 UpdateWrapper 用法(更新條件構造)
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.mpdemo.entity.User;
// 1. 條件更新:將用户名 "張三" 的年齡改為 25,郵箱改為 zhangsan@qq.com
public boolean updateUserByWrapper() {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
// 設置更新字段
updateWrapper.set("age", 25)
.set("email", "zhangsan@qq.com")
// 設置更新條件
.eq("user_name", "張三")
.eq("is_deleted", 0);
return userService.update(updateWrapper);
}
5.4 LambdaUpdateWrapper 用法(推薦)
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.example.mpdemo.entity.User;
// 1. 條件更新:年齡 > 30 的用户,年齡統一加 1
public boolean updateUserByLambdaWrapper() {
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
// 更新字段:age = age + 1
lambdaUpdateWrapper.setSql("age = age + 1")
// 條件:age > 30 且未刪除
.gt(User::getAge, 30)
.eq(User::getIsDeleted, 0);
return userService.update(lambdaUpdateWrapper);
}
// 2. 動態更新:只更新非 null 的字段
public boolean updateUserDynamic(User user) {
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
// 條件:根據主鍵 ID 更新
lambdaUpdateWrapper.eq(User::getId, user.getId());
// 若 userName 不為 null,更新用户名
if (user.getUserName() != null) {
lambdaUpdateWrapper.set(User::getUserName, user.getUserName());
}
// 若 age 不為 null,更新年齡
if (user.getAge() != null) {
lambdaUpdateWrapper.set(User::getAge, user.getAge());
}
return userService.update(lambdaUpdateWrapper);
}
5.5 常用條件構造方法(全量彙總)
|
方法名 |
功能描述 |
示例(Lambda 形式) |
|
|
等於(=) |
|
|
|
不等於(!=) |
|
|
|
大於(>) |
|
|
|
大於等於(>=) |
|
|
|
小於(<) |
|
|
|
小於等於(<=) |
|
|
|
介於兩者之間(between) |
|
|
|
不介於兩者之間(not between) |
|
|
|
模糊查詢(like %val%) |
|
|
|
左模糊(like %val) |
|
|
|
右模糊(like val%) |
|
|
|
不匹配模糊查詢(not like) |
|
|
|
字段為 null |
|
|
|
字段不為 null |
|
|
|
包含在集合中(in) |
|
|
|
不包含在集合中(not in) |
|
|
|
子查詢 in(in (sql)) |
|
|
|
分組(group by) |
|
|
|
升序排序(order by asc) |
|
|
|
降序排序(order by desc) |
|
|
|
分組後條件(having) |
|
|
|
並且(and) |
|
|
|
或者(or) |
|
|
|
存在子查詢(exists (sql)) |
|
|
|
不存在子查詢(not exists) |
|
|
|
更新字段(update 時用) |
|
|
|
自定義更新 SQL(update 時用) |
|
六、核心特性:插件機制(分頁、樂觀鎖等)
MP 提供了一系列開箱即用的插件,通過簡單配置即可啓用,覆蓋分頁、樂觀鎖、邏輯刪除、性能分析等常用場景。
6.1 分頁插件(最常用)
MP 的分頁插件支持物理分頁(而非內存分頁),自動攔截查詢語句添加 limit 條件,支持 MySQL、Oracle、PostgreSQL 等主流數據庫。
6.1.1 配置分頁插件(Spring Boot 3.x)
創建 MP 配置類,註冊分頁插件:
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加分頁插件,指定數據庫類型(MySQL)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
6.1.2 分頁查詢用法
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.mpdemo.entity.User;
import java.util.List;
// 1. 基礎分頁(無條件)
public IPage<User> getUserPage(Integer pageNum, Integer pageSize) {
// Page 構造器:pageNum(頁碼,從 1 開始),pageSize(每頁條數)
Page<User> page = new Page<>(pageNum, pageSize);
// 調用 Service 層 page 方法
return userService.page(page);
}
// 2. 條件分頁(帶 Lambda 條件構造器)
public IPage<User> getUserPageByCondition(Integer pageNum, Integer pageSize, String userName) {
Page<User> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
if (userName != null) {
lambdaQueryWrapper.like(User::getUserName, userName);
}
// 分頁 + 條件查詢
IPage<User> userPage = userService.page(page, lambdaQueryWrapper);
// IPage 核心屬性(返回給前端)
long total = userPage.getTotal(); // 總記錄數
long pages = userPage.getPages(); // 總頁數
List<User> records = userPage.getRecords(); // 當前頁數據
boolean hasNext = userPage.hasNext(); // 是否有下一頁
boolean hasPrevious = userPage.hasPrevious(); // 是否有上一頁
return userPage;
}
// 3. 自定義 XML SQL 分頁(若需自定義 SQL,分頁插件同樣生效)
// Mapper 接口方法:
// IPage<User> selectUserByAgePage(Page<User> page, @Param("minAge") Integer minAge);
// XML 中無需寫 limit,分頁插件自動添加:
// <select id="selectUserByAgePage" resultType="com.example.mpdemo.entity.User">
// select * from mp_user where age >= #{minAge}
// </select>
6.2 樂觀鎖插件(解決併發更新衝突)
樂觀鎖基於「版本號機制」,適用於併發場景下避免數據覆蓋,核心邏輯:
- 實體類添加版本號字段(如
version),標記@Version註解; - 更新時,SQL 自動拼接
where version = 原版本號; - 若版本號不匹配(已被其他線程更新),更新失敗(返回影響行數 0)。
6.2.1 配置樂觀鎖插件
在 MyBatisPlusConfig 中添加樂觀鎖插件:
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分頁插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 樂觀鎖插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
6.2.2 實體類添加版本號字段
import com.baomidou.mybatisplus.annotation.Version;
@Data
@TableName("mp_user")
public class User {
// ... 其他字段省略 ...
// 樂觀鎖版本號字段(數據庫表需添加 version 字段,默認值 0)
@Version
private Integer version;
}
6.2.3 樂觀鎖使用示例
import com.example.mpdemo.entity.User;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 併發更新用户年齡(樂觀鎖示例)
@Transactional
public boolean updateUserAge(Long userId, Integer newAge) {
// 1. 查詢用户(獲取當前版本號)
User user = getById(userId);
if (user == null) {
return false;
}
// 2. 修改年齡
user.setAge(newAge);
// 3. 更新(SQL 自動拼接 where version = user.getVersion())
boolean success = updateById(user);
if (!success) {
// 更新失敗(版本號不匹配),可重試或拋異常
throw new RuntimeException("併發更新衝突,請重試");
}
return true;
}
}
6.3 邏輯刪除插件(假刪除)
邏輯刪除是「假刪除」,通過字段標記數據是否刪除(如 is_deleted),查詢時自動過濾已刪除數據,避免數據物理刪除後無法恢復。
6.3.1 配置(已在 application.yml 中全局配置,無需額外插件)
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDeleted # 邏輯刪除字段名(實體類字段名)
logic-delete-value: 1 # 已刪除值
logic-not-delete-value: 0 # 未刪除值
6.3.2 實體類配置(可選,覆蓋全局)
import com.baomidou.mybatisplus.annotation.TableLogic;
@Data
@TableName("mp_user")
public class User {
// ... 其他字段省略 ...
// 邏輯刪除字段(覆蓋全局配置)
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
}
6.3.3 邏輯刪除使用示例
// 1. 刪除操作(自動改為更新 is_deleted = 1)
userService.removeById(1L);
// 執行的 SQL:update mp_user set is_deleted = 1 where id = 1 and is_deleted = 0
// 2. 查詢操作(自動過濾 is_deleted = 1 的數據)
userService.getById(1L);
// 執行的 SQL:select * from mp_user where id = 1 and is_deleted = 0
userService.list();
// 執行的 SQL:select * from mp_user where is_deleted = 0
// 3. 如需查詢已刪除數據,需手動添加條件
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getIsDeleted, 1);
userService.list(queryWrapper);
6.4 性能分析插件(開發環境調試)
性能分析插件可打印 SQL 執行時間、參數、結果,方便開發環境調試慢查詢,生產環境需關閉。
6.4.1 配置性能分析插件
import com.baomidou.mybatisplus.extension.plugins.inner.SqlExplainInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class MyBatisPlusConfig {
// 僅在 dev 環境啓用(通過 @Profile 控制)
@Profile({"dev"})
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor interceptor = new PerformanceInterceptor();
// 設置 SQL 執行超時時間(單位:ms),超時則拋異常
interceptor.setMaxTime(500);
// 格式化 SQL 輸出(美觀易讀)
interceptor.setFormat(true);
return interceptor;
}
}
七、進階用法:自定義 SQL(兼容 MyBatis 原生)
MP 完全兼容 MyBatis 原生用法,當 CRUD 接口和條件構造器無法滿足複雜需求(如多表關聯查詢、複雜子查詢)時,可通過 XML 或註解自定義 SQL。
7.1 註解方式自定義 SQL(簡單 SQL 推薦)
在 Mapper 接口中直接用 @Select、@Insert 等註解編寫 SQL:
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper extends BaseMapper<User> {
// 1. 簡單查詢:根據用户名和年齡查詢用户(註解 SQL)
@Select("select * from mp_user where user_name = #{userName} and age = #{age} and is_deleted = 0")
User selectByUserNameAndAge(@Param("userName") String userName, @Param("age") Integer age);
// 2. 結合條件構造器:自定義 SQL + 動態條件(${ew.customSqlSegment} 是固定語法)
@Select("select u.id, u.user_name, u.age from mp_user u ${ew.customSqlSegment}")
List<User> selectCustomByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
// 3. 分頁查詢:自定義 SQL + 分頁插件
@Select("select * from mp_user where age >= #{minAge} and is_deleted = 0")
IPage<User> selectByAgePage(IPage<User> page, @Param("minAge") Integer minAge);
}
7.2 XML 方式自定義 SQL(複雜 SQL 推薦)
7.2.1 配置 XML 路徑(已在 application.yml 中配置)
mybatis-plus:
mapper-locations: classpath:mapper/*.xml # XML 文件放在 resources/mapper 目錄下
7.2.2 創建 XML 文件(resources/mapper/UserMapper.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 命名空間必須與 Mapper 接口全路徑一致 -->
<mapper namespace="com.example.mpdemo.mapper.UserMapper">
<!-- 1. 多表關聯查詢(用户表 + 訂單表,查詢用户及關聯的訂單數) -->
<select id="selectUserWithOrderCount" resultType="java.util.Map">
select
u.id, u.user_name, u.age, count(o.id) as order_count
from
mp_user u
left join
mp_order o on u.id = o.user_id
where
u.is_deleted = 0
group by
u.id
</select>
<!-- 2. 動態 SQL(結合 MP 條件構造器,${ew.customSqlSegment} 拼接條件) -->
<select id="selectUserByXmlWrapper" resultType="com.example.mpdemo.entity.User">
select * from mp_user
<where>
${ew.customSqlSegment}
</where>
</select>
<!-- 3. 批量插入(優化性能,比循環 insert 高效) -->
<insert id="batchInsertUser">
insert into mp_user (id, user_name, age, email, is_deleted, create_time, update_time)
values
<foreach collection="list" item="user" separator=",">
(#{user.id}, #{user.userName}, #{user.age}, #{user.email}, #{user.isDeleted}, #{user.createTime}, #{user.updateTime})
</foreach>
</insert>
</mapper>
7.2.3 Mapper 接口關聯 XML 方法
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.mpdemo.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper extends BaseMapper<User> {
// 關聯 XML 中的 selectUserWithOrderCount 方法
List<Map<String, Object>> selectUserWithOrderCount();
// 關聯 XML 中的 selectUserByXmlWrapper 方法(結合條件構造器)
List<User> selectUserByXmlWrapper(@Param("ew") Wrapper<User> wrapper);
// 關聯 XML 中的 batchInsertUser 方法
int batchInsertUser(@Param("list") List<User> userList);
}
7.3 多表關聯查詢(MP 增強方案)
除了原生 XML 多表查詢,MP 還提供了 @TableName 關聯、LambdaQueryChainWrapper 鏈式查詢等增強方式,這裏推薦 XML 方式(最靈活)和 註解關聯方式(簡單多表場景)。
註解關聯示例(一對一)
// 訂單實體(關聯用户表)
@Data
@TableName("mp_order")
public class Order {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long userId; // 關聯用户表主鍵
private String orderNo; // 訂單號
private BigDecimal amount; // 金額
private Integer isDeleted;
// 一對一關聯用户信息(非數據庫字段,查詢時通過註解關聯)
@TableField(exist = false)
private User user;
}
// Mapper 接口註解關聯查詢
public interface OrderMapper extends BaseMapper<Order> {
@Select("select o.*, u.user_name, u.age from mp_order o " +
"left join mp_user u on o.user_id = u.id " +
"where o.id = #{id} and o.is_deleted = 0")
// @ResultMap 映射關聯字段(也可使用 @Result 逐個映射)
@ResultMap("orderUserMap")
Order selectOrderWithUser(@Param("id") Long id);
}
八、進階用法:代碼生成器(AutoGenerator)
MP 代碼生成器能根據數據庫表結構,自動生成 Entity、Mapper、Service、Controller、XML 全套代碼,支持自定義模板,開發效率直接翻倍。
8.1 引入代碼生成器依賴
<!-- MyBatis-Plus 代碼生成器核心依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.5</version>
</dependency>
<!-- 模板引擎(MP 支持 Velocity、Freemarker、Beetl,這裏用 Velocity) -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
8.2 編寫代碼生成器配置類
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
// 數據庫連接配置
String url = "jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String username = "root";
String password = "123456";
// 代碼生成核心配置
FastAutoGenerator.create(url, username, password)
// 1. 全局配置
.globalConfig(builder -> {
builder.author("your-name") // 作者名
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 代碼輸出目錄(項目 java 目錄)
.commentDate("yyyy-MM-dd") // 註釋日期格式
.disableOpenDir() // 生成後不自動打開文件夾
.enableSwagger() // 啓用 Swagger 註解(需引入 Swagger 依賴)
.fileOverride(); // 覆蓋已存在的文件
})
// 2. 包配置(代碼存放的包路徑)
.packageConfig(builder -> {
builder.parent("com.example.mpdemo") // 父包名
.entity("entity") // 實體類包名
.mapper("mapper") // Mapper 接口包名
.service("service") // Service 接口包名
.serviceImpl("service.impl") // Service 實現類包名
.controller("controller") // Controller 包名
.xml("mapper.xml") // XML 文件包名(resources 目錄下)
.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper")); // XML 輸出目錄
})
// 3. 策略配置(表、字段、代碼生成規則)
.strategyConfig(builder -> {
builder.addInclude("mp_user", "mp_order") // 要生成代碼的表名(多個表用逗號分隔)
.addTablePrefix("mp_") // 表前綴(生成實體類時自動去除前綴,如 mp_user → User)
// 實體類策略
.entityBuilder()
.enableLombok() // 啓用 Lombok 註解(生成 @Data 等)
.enableTableFieldAnnotation() // 為字段添加 @TableField 註解
.idType(com.baomidou.mybatisplus.generator.config.rules.IdType.ASSIGN_ID) // 主鍵生成策略
.logicDeleteFieldName("isDeleted") // 邏輯刪除字段名
.enableChainModel() // 啓用鏈式調用(生成 set 方法返回 this)
// Mapper 策略
.mapperBuilder()
.enableBaseResultMap() // 啓用 BaseResultMap(XML 中生成結果映射)
.enableBaseColumnList() // 啓用 BaseColumnList(XML 中生成字段列表)
.enableMapperAnnotation() // 為 Mapper 接口添加 @Mapper 註解
// Service 策略
.serviceBuilder()
.formatServiceFileName("%sService") // Service 接口命名格式(如 UserService)
.formatServiceImplFileName("%sServiceImpl") // Service 實現類命名格式(如 UserServiceImpl)
// Controller 策略
.controllerBuilder()
.enableRestStyle() // 啓用 RestController 註解
.enableHyphenStyle(); // URL 中駝峯轉連字符(如 userInfo → user-info)
})
// 4. 模板引擎配置(使用 Velocity)
.templateEngine(new VelocityTemplateEngine())
// 執行生成
.execute();
}
}
8.3 生成代碼後效果
運行 CodeGenerator.main() 方法,會自動生成以下文件:
src/main/java/com/example/mpdemo/
├── entity/
│ ├── User.java
│ └── Order.java
├── mapper/
│ ├── UserMapper.java
│ └── OrderMapper.java
├── service/
│ ├── UserService.java
│ ├── OrderService.java
│ └── impl/
│ ├── UserServiceImpl.java
│ └── OrderServiceImpl.java
├── controller/
│ ├── UserController.java
│ └── OrderController.java
src/main/resources/mapper/
├── UserMapper.xml
└── OrderMapper.xml
生成的代碼已包含 CRUD 接口、註解配置、分頁支持等,可直接用於開發。
九、實戰案例:完整業務流程(用户管理)
結合以上所有特性,實現一個完整的「用户管理」業務流程,包含新增、查詢、更新、刪除、分頁、條件查詢等功能。
9.1 實體類(User.java)
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("mp_user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@TableField(value = "user_name")
private String userName;
private Integer age;
private String email;
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
9.2 自動填充處理器(處理 createTime 和 updateTime)
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入時填充
@Override
public void insertFill(MetaObject metaObject) {
// 填充 createTime 和 updateTime 為當前時間
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
// 更新時填充
@Override
public void updateFill(MetaObject metaObject) {
// 填充 updateTime 為當前時間
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
9.3 Mapper 接口(UserMapper.java)
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
// 無需自定義方法,BaseMapper 已滿足需求
}
9.4 Service 接口與實現類
// UserService.java
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mpdemo.entity.User;
import java.util.List;
public interface UserService extends IService<User> {
// 條件分頁查詢
IPage<User> getUserPage(Page<User> page, String userName, Integer minAge, Integer maxAge);
}
// UserServiceImpl.java
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import com.example.mpdemo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public IPage<User> getUserPage(Page<User> page, String userName, Integer minAge, Integer maxAge) {
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 動態條件
if (userName != null && !userName.isEmpty()) {
lambdaQueryWrapper.like(User::getUserName, userName);
}
if (minAge != null) {
lambdaQueryWrapper.ge(User::getAge, minAge);
}
if (maxAge != null) {
lambdaQueryWrapper.le(User::getAge, maxAge);
}
// 過濾已刪除數據
lambdaQueryWrapper.eq(User::getIsDeleted, 0);
// 分頁查詢
return page(page, lambdaQueryWrapper);
}
}
9.5 Controller 接口(UserController.java)
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.service.UserService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
// 新增用户
@PostMapping
public boolean addUser(@RequestBody User user) {
return userService.save(user);
}
// 批量新增用户
@PostMapping("/batch")
public boolean addUserBatch(@RequestBody List<User> userList) {
return userService.saveBatch(userList);
}
// 根據 ID 查詢用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
// 條件分頁查詢
@GetMapping("/page")
public IPage<User> getUserPage(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String userName,
@RequestParam(required = false) Integer minAge,
@RequestParam(required = false) Integer maxAge) {
Page<User> page = new Page<>(pageNum, pageSize);
return userService.getUserPage(page, userName, minAge, maxAge);
}
// 根據 ID 更新用户
@PutMapping
public boolean updateUser(@RequestBody User user) {
return userService.updateById(user);
}
// 根據 ID 刪除用户(邏輯刪除)
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.removeById(id);
}
}
9.6 接口測試(Postman 示例)
- 新增用户:
POST /user,請求體:
{
"userName": "張三",
"age": 25,
"email": "zhangsan@qq.com"
}
- 分頁查詢:
GET /user/page?pageNum=1&pageSize=10&userName=張&minAge=18 - 更新用户:
PUT /user,請求體:
{
"id": 1425678901234567890,
"userName": "張三三",
"age": 26
}
- 刪除用户:
DELETE /user/1425678901234567890
十、最佳實踐與避坑指南
10.1 最佳實踐
- 命名規範:
- 數據庫表名、列名使用下劃線命名(如
mp_user、user_name); - 實體類名使用 Pascal 命名(如
User),屬性使用駝峯命名(如userName); - Mapper 接口名以
Mapper結尾(如UserMapper),Service 接口以Service結尾(如UserService)。
- 性能優化:
- 批量操作優先使用
saveBatch、updateBatchById(MP 已優化,比循環單條操作高效); - 複雜查詢使用 XML 方式,便於優化 SQL;
- 分頁查詢避免查詢全表,合理設置
pageSize; - 啓用 MyBatis 二級緩存(需實體類實現
Serializable),減少重複查詢。
- 安全規範:
- 避免直接使用用户輸入作為 SQL 條件(MP 條件構造器已防 SQL 注入,無需手動處理);
- 生產環境關閉 SQL 打印和性能分析插件;
- 數據庫密碼使用配置中心存儲(如 Nacos、Apollo),避免硬編碼。
- 代碼結構:
- 複雜業務邏輯放在 Service 層,Mapper 層僅負責數據訪問;
- 自定義 SQL 優先使用 XML 方式,便於維護;
- 統一異常處理(如樂觀鎖衝突、分頁參數錯誤)。
10.2 常見坑與解決方案
- 字段名與列名不匹配:
- 原因:未開啓駝峯命名轉換,或實體字段與數據庫列名差異過大;
- 解決方案:開啓
map-underscore-to-camel-case: true,或使用@TableField(value = "列名")顯式映射。
- 分頁插件不生效:
- 原因:未配置分頁插件,或數據庫類型錯誤;
- 解決方案:在
MyBatisPlusConfig中註冊PaginationInnerInterceptor,並指定正確的DbType。
- 樂觀鎖更新失敗:
- 原因:版本號字段未加
@Version註解,或更新時未攜帶版本號; - 解決方案:實體類添加
@Version註解,查詢用户時獲取版本號,更新時傳入。
- 邏輯刪除未生效:
- 原因:未配置
logic-delete-field,或字段類型不匹配; - 解決方案:在
application.yml中配置全局邏輯刪除字段,確保實體字段與數據庫列類型一致(如tinyint)。
- 代碼生成器無法生成 XML 文件:
- 原因:未配置
pathInfo指定 XML 輸出目錄,或目錄不存在; - 解決方案:在
packageConfig中設置pathInfo(Collections.singletonMap(OutputFile.xml, 目錄路徑)),確保目錄已創建。
十一、總結
MyBatis-Plus 的核心價值是「簡化開發、提高效率」,通過「CRUD 接口+條件構造器+插件機制+代碼生成器」四大核心能力,覆蓋了從簡單查詢到複雜業務的絕大多數場景,同時保持了對 MyBatis 原生的完全兼容。
學習 MP 的關鍵是:
- 掌握 Entity 註解與數據庫表的映射關係;
- 熟練使用 BaseMapper/IService 接口實現無 SQL 開發;
- 靈活運用條件構造器編寫動態 SQL;
- 合理配置插件(分頁、樂觀鎖等)解決通用問題;
- 用代碼生成器提升開發效率。