MyBatis-Plus高效開發(fā)實戰(zhàn)指南
一. MyBatis-Plus 介紹
MyBatis-Plus(簡稱 MP)是?個MyBatis的增強工具,在MyBatis的基礎上只做增強不做改變,為簡化開發(fā).提高效率而生 。
特性:
• 潤物無聲:只做增強不做改變,引入它不會對現有?程產生影響,如絲般順滑.
• 效率至上:只需簡單配置,即可快速進行單表CRUD操作,從而節(jié)省大量時間.
• 豐富功能:代碼生成、自動分頁、邏輯刪除、自動填充、攔截器等功能?應俱全.
• 廣泛認可:連續(xù)5年獲得開源中國年度最佳開源項目殊榮,Github累計16KStar.

支持數據庫: PostgreSQL , MySQL , MariaDB , Oracle , SQLServer , OceanBase , H2 , DB2...(任何能使用MyBatis進行增刪改查,并且支持標準SQL的數據庫應該都在MyBatis-Plus的支持范圍內)
更多介紹,可查看 MyBatis-Plus 官網:https://baomidou.com/
二. MyBatis-Plus 使用
2.1 準備工作
數據庫數據準備:
-- 創(chuàng)建數據庫 DROP DATABASE IF EXISTS mybatis_test; CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4; -- 使?數據數據 USE mybatis_test; -- 創(chuàng)建表[??表] DROP TABLE IF EXISTS user_info; CREATE TABLE `user_info` ( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT, `user_name` VARCHAR ( 127 ) NOT NULL, `password` VARCHAR ( 127 ) NOT NULL, `age` TINYINT ( 4 ) NOT NULL, `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-? 0-默認', `phone` VARCHAR ( 15 ) DEFAULT NULL, `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-刪除', `create_time` DATETIME DEFAULT now(), `update_time` DATETIME DEFAULT now(), PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加??信息 INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone ) VALUES ( 'admin', 'admin', 18, 1, '18612340001' ); INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone ) VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' ); INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone ) VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' ); INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone ) VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
添加MyBatis-Plus依賴與MySQL數據庫依賴:
引入 MyBatis-Plus Starter 依賴:
Spring Boot2
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.15</version>
</dependency>Spring Boot3
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.15</version>
</dependency>Spring Boot4 (自3.5.13開始)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>3.5.15</version>
</dependency>注意:不同的Spring版本引入不同的MyBatis-Plus依賴得版本不同(根據Spring版本添加相應版本得依賴)
引入MySQL數據庫依賴:
<dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>
配置數據庫
application.yml文件,配置內容如下:
# 數據庫連接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# 控制臺打印 SQL日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 2.2 編碼
為數據庫中表創(chuàng)建實體類:
@Data
public class UserInfo {
private Integer id;
private String userName;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
編寫Mapper接口類:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
我們需要我們創(chuàng)建的這個 Mapper接口類 去繼承 BaseMapper 這個接口
BaseMapper 這個接口是個泛型接口,填的是我們方法返回內容的對象的類型
BaseMapper中定義的方法:

MybatisPlus提供了?個基礎的 BaseMapper 接口,已經實現了單表的CRUD, 我們自定義的 Mapper只需要繼承這個BaseMapper, 就無需自己實現單表CRUD了
2.3 單元測試
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
UserInfoMapper userInfoMapper;
@Test
void testInsert() {
UserInfo user = new UserInfo();
user.setUserName("xiaoming");
user.setPassword("123456");
user.setAge(11);
user.setGender(0);
user.setPhone("18610001234");
userInfoMapper.insert(user);
}
@Test
void testSelectById() {
UserInfo user = userInfoMapper.selectById(1L);
System.out.println("user: " + user);
}
@Test
void testSelectByIds() {
List<UserInfo> users = userInfoMapper.selectByIds(List.of(1, 2, 3, 4));
users.forEach(System.out::println);
}
@Test
void testUpdateById() {
UserInfo user = new UserInfo();
user.setId(1);
user.setPassword("4444444");
userInfoMapper.updateById(user);
}
@Test
void testDelete() {
userInfoMapper.deleteById(5);
}
}執(zhí)行后的測試用例后的數據庫:

三. MyBatis-Plus復雜操作
3.1 常見注解
3.1.1 @TableName
我們來看下面這個日志

發(fā)現:在我們并沒有告訴要操作表的信息時,MyBatis-Plus就已經知道了我們要操作的是哪一張表,這是為什么----原因:MyBatis-Plus會通過 我們在 BaseMapper<>中傳入的實體類來推斷對應數據庫中的表名(推斷列子與規(guī)律如下表所示)
| 實體類名 | 表名 | 轉換邏輯 |
|---|---|---|
UserInfo | user_info | 駝峰拆分:User + Info → 轉小寫 + 下劃線連接 → user_info |
Userinfo | userinfo | 無駝峰分隔 → 直接全小寫 → userinfo |
BookInfo | book_info | 駝峰拆分: |
如果我們設定的實體類經上述規(guī)律推斷出來的表名與數據庫中的表名對應不上時,就會報錯,這時我們就要使用 @TableName 注解來解決問題
代碼如下:(@TableName中填寫的是實體類對應的數據庫中的表名)
@Data
@TableName("user_info")//指定對應的數據庫中的表名
public class UserInfo {
@TableId(value="id",type=IdType.AUTO)
private Integer userid;
private String userName;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
3.1.2 @TableField
在我們不添加 @TableField注解前,MyBatis-Plus對于字段與屬性的映射關系,也和表名一樣,是通過自動判斷轉發(fā)來的,當轉化的名稱與數據庫中屬性名對應不上式,我們就需要添@TableField注解,來對應映射關系。如下面代碼所示:
@Data
@TableName("user_info")//指定對應的數據庫中的表名
public class UserInfo {
@TableId(value="id",type=IdType.AUTO)
private Integer userid;
private String userName;
private String password;
private Integer age;
private Integer gender;
private String phone;
@TableField("delete_flag")//只舉這一個例子
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}3.1.3 @TableId
注意:
- 在沒有添加 @TableId注解之前,MyBatis-Plus默認 id 為主鍵
- 一個實體表類中只能有一個主鍵
在執(zhí)行 testInsert() (該方法沒有傳入主鍵id的值)后,我們發(fā)現我們增加的這條數據的主鍵并沒有自增,而是一個隨機生成的數字 ----- 原因:由于 MyBatis-Plus 默認 id為主鍵,且針對主鍵的默認賦值策略是 IdType.ASSIGN_ID(雪花算法)—— 該策略會由 MP 自動生成 19 位分布式唯一的隨機長數字,而非依賴數據庫自增,因此最終插入的主鍵是隨機數,而非數據庫自增的連續(xù)值。
如何解決:添加@TableId注解并且修改主鍵指定自增類型的主鍵策略
@TableId注解 源碼:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
String value() default "";
IdType type() default IdType.NONE;
}
value:主鍵的名稱,如果實體類中主鍵的名稱與數據庫中主鍵的名稱不一致是,需通過value(其中填寫對應數據庫中主鍵的名稱);一致時可不填寫
type:指定自增類型的主鍵策略(默認為IdType.NONE)
| IdType 取值 | 含義 | 適用場景 |
|---|---|---|
AUTO | 數據庫自增生成主鍵 | 單體項目、表主鍵是自增字段(MySQL 的 AUTO_INCREMENT) |
ASSIGN_ID | MP 用雪花算法生成 19 位長數字 | 分布式項目、需要全局唯一 ID |
INPUT | 手動輸入主鍵值(MP 不生成) | 主鍵是業(yè)務編號(如訂單號)、需手動賦值的場景 |
NONE | 無指定(默認兜底為 ASSIGN_ID) | 不推薦直接用,需顯式指定 AUTO/ASSIGN_ID |
將 主鍵 id 修改為自增:代碼如下
@Data
public class UserInfo {
@TableId(value="id",type=IdType.AUTO)
private Integer userid;
private String userName;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
注意:由于我們在前面生成了一個主鍵為隨機數的數據,因此我們需要修改該表自動遞增的起始數

再執(zhí)行一下測試用例:
@Test
void testInsert() {
UserInfo user = new UserInfo();
user.setUserName("huahua");
user.setPassword("666666");
user.setAge(11);
user.setGender(0);
user.setPhone("18610001234");
userInfoMapper.insert(user);
}執(zhí)行后數據庫----id開始自增

3.2 條件構造器
入門程序里的使用, 都是簡單的CRUD, 但是在實際的應用場景中,我們還需要使用更復雜的操作, MyBatisPlus 也給我們提供了相應的支持.
MyBatis-Plus 提供了?套強大的條件構造器(Wrapper),用于構建復雜的數據庫查詢條件.Wrapper類 允許開發(fā)者以鏈式調用的方式構造查詢條件,無需編寫繁瑣的 SQL 語句, 從而提高開發(fā)效率并減少 SQL 注入的風險.
以下是主要的 Wrapper 類及其功能:
| 類名 | 核心定位 | 核心特性 / 拓展功能 |
|---|---|---|
| AbstractWrapper | 抽象基類(所有 Wrapper 父類) | 提供所有 Wrapper 類共有的方法和屬性(如條件拼接、排序、分頁等基礎能力) |
| QueryWrapper | 通用查詢條件構造器 | 繼承 AbstractWrapper,額外拓展 select() 方法,支持手動指定查詢字段(如只查 id、username) |
| UpdateWrapper | 通用更新條件構造器 | 繼承 AbstractWrapper,專注于 UPDATE 操作,支持拼接更新條件 + 手動指定 SET 字段值 |
| LambdaQueryWrapper | Lambda 版查詢構造器 | 基于 QueryWrapper,通過 Lambda 表達式引用實體類屬性(如 User::getAge),替代硬編碼字段名 |
| LambdaUpdateWrapper | Lambda 版更新構造器 | 基于 UpdateWrapper,通過 Lambda 表達式指定更新字段和條件,替代硬編碼字段名 |
具體可查看官網:https://baomidou.com/guides/wrapper/
接下來我們來看具體如何實現:
3.2.1 QueryWrapper
QueryWrapper并不只用于查詢語句,無論是修改, 刪除, 查詢,都可以使用 QueryWrapper來構建查詢條件.
QueryWrapper 最核心的兩大能力:指定查詢字段(select) + 構建查詢條件(where)
完成以下SQL查詢:(查詢)
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username "%min%"
測試代碼如下:
@Test
void testQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<UserInfo>()
.select("user_name","password","age")
.eq("age",18)
.like("user_name","min");//鏈式調用
List<UserInfo> userInfoList=userInfoMapper.selectList(queryWrapper);
}
完成下述SQL查詢:(更新)
UPDATE user_info SET delete_flag=? WHERE age < 20
測試代碼如下:
@Test
void testUpdateByQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<UserInfo>()
.lt("age",18); //構造條件 where age<18
UserInfo userInfo=new UserInfo();
userInfo.setDeleteFlag(1);
userInfoMapper.update(userInfo,queryWrapper);
}
MyBatis-Plus 條件構造器核心比較方法速查表:(注意:所有基于 AbstractWrapper 派生的條件構造器都可以使用)
| 方法名 | 中文含義 | 對應 SQL 運算符 |
|---|---|---|
lt | 小于 | < |
le | 小于等于 | <= |
ge | 大于等于 | >= |
gt | 大于 | > |
eq | 等于 | = |
ne | 不等于 | <>/!= |
完成下述SQL查詢:(刪除)
DELETE FROM user_info WHERE age = 18
測試代碼:
@Test
void testDeleteByQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper =new QueryWrapper<UserInfo>()
.eq("age",18);
userInfoMapper.delete(queryWrapper);
}3.3.2 UpdateWrapper
對于更新, 我們也可以直接使用 UpdateWrapper, 在不創(chuàng)建實體對象的情況下, 直接設置更新字段和條件.
UpdateWrapper 最核心的兩大能力:構建字段賦值(set)+ 構建更新條件條件(where)
完成下述SQL查詢:(基礎更新):
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
測試代碼:
@Test
void testUpdateByUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<UserInfo>()
.set("delete_flag",0)
.set("age", 5)
.in("id",List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}完成下述SQL查詢:(基于SQL更新)
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
測試代碼:
@Test
void testUpdateBySQLUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<UserInfo>()
.setSql("age=age+10")
.in("id",List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}| 對比項 | set() 方法 | setSql() 方法 |
|---|---|---|
| 賦值方式 | 靜態(tài)值賦值(字段 = 固定值) | 自定義 SQL 片段賦值 |
| 適用場景 | 簡單賦值(如 status = 1) | 復雜賦值(如字段自增、函數計算) |
| 語法 | set("字段名", 固定值) | setSql("SQL片段") |
3.3.3 LambdaQueryWrapper
QueryWrapper 和 UpdateWrapper存在?個問題,就是需要寫死數據庫列名字段名 , 如果字段名發(fā)生變更,可能會因為測試不到位釀成事故. MyBatis-Plus給我們提供了?種基于Lambda表達式的條件構造器,它通過Lambda表達式來引用實體類的屬性,從而避免了硬編碼字段名,也提高了代碼的可讀性和可維護性.
接下來我們看下具體使用:
寫法一:
@Test
void testLambdaQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();
queryWrapper.lambda()
.select(UserInfo::getUserName, UserInfo::getPassword,UserInfo::getAge)
.eq(UserInfo::getUserid, 1);
userInfoMapper.selectList(queryWrapper);
}寫法二:
@Test
void testLambdaQueryWrapper(){
LambdaQueryWrapper<UserInfo> lambdaQueryWrapper=new LambdaQueryWrapper<UserInfo>()
.select(UserInfo::getUserName, UserInfo::getPassword,UserInfo::getAge)
.eq(UserInfo::getUserid, 1);
userInfoMapper.selectList(lambdaQueryWrapper);
}3.3.4 LambdaUpdateWrapper
LambdaUpdateWrapper 用法和 LambdaQueryWrapper 相似
@Test
void testLambdUpdateByUpdateWrapper(){
//同樣有兩種寫法,這里只寫一種
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();
updateWrapper.lambda()
.set(UserInfo::getDeleteFlag, 0)
.set(UserInfo::getAge, 5)
.in(UserInfo::getUserId, List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}
3.3 自定義SQL
在實際的開發(fā)中, MyBatis-Plus提供的操作不能滿足我們的實際需求, MyBatis-Plus 也提供了自定義 SQL的功能, 我們可以利用Wrapper構造查詢條件,再結合Mapper編寫SQL
注意事項:
• 參數命名:在自定義SQL時,傳遞Wrapper對象作為參數時,參數名必須為ew ,或者使用注解 @Param(Constants.WRAPPER) 明確指定參數為 Wrapper 對象.
• 使用${ew.customSqlSegment} :在SQL語句中,使用 ${ew.customSqlSegment} 來 引用Wrapper對象生成的SQL片段.
• 不支持基于entity的where語句:自定義SQL時,Wrapper對象不會基于實體類自動生成 where子句,你需要手動編寫完整的SQL語句.(即必須使用占位符)
代碼示例1:
select id,username,password,age FROM user_info WHERE username = "admin"
Mapper接口:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
@Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
List<UserInfo> queryUserByCustom( @Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);//括號里等同于 Wrapper<UserInfo> ew
}測試代碼:
@Test
void queryUserByCustom() {
QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<UserInfo>()
.eq("username","admin");
List<UserInfo> userInfo=userInfoMapper.queryUserByCustom(queryWrapper);
System.out.println(userInfo);
}代碼示例二:
MyBatis-Plus 在 MyBatis 的基礎上只做增強不做改變,所以也支持XML的實現方式上述功能也可以使用XML的方式完成
1. 配置mapper路徑
mybatis-plus: mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml
2. 定義?法
@Mapper
public interface UserInfoMapper extends BaseMapper {
List queryUserByCustom2(@Param(Constants.WRAPPER) Wrapper wrapper);
}3. 編寫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 namespace="com.bite.mybatis.plus.mapper.UserInfoMapper">
<select id="queryUserByCustom2">
select id,username,password,age FROM user_info ${ew.customSqlSegment}
</select>
</mapper>4. 測試:
@Test
void testQueryUserByCustom2(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
.eq("username","admin");
userInfoMapper.queryUserByCustom2(queryWrapper).forEach(System.out::println);
}
代碼示例3:
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
Mapper接口:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
@Update("UPDATE user_info SET age = age+ #{addAge} ${ew.customSqlSegment}")
void updateUserByCustom(@Param("addAge") Integer add ,@Param("ew") Wrapper<UserInfo> wrapper);
}測試代碼:
@Test
void updateUserByCustom() {
QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<UserInfo>()
.in("id",List.of(1,2,3));
userInfoMapper.updateUserByCustom(10,queryWrapper);
}到此這篇關于MyBatis-Plus高效開發(fā)實戰(zhàn)指南的文章就介紹到這了,更多相關MyBatis-Plus高效開發(fā)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
如何在Java SpringBoot項目中配置動態(tài)數據源你知道嗎
這篇文章主要介紹了SpringBoot如何在運行時動態(tài)添加數據源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2021-09-09
Springboot中登錄后關于cookie和session攔截問題的案例分析
這篇文章主要介紹了Springboot中登錄后關于cookie和session攔截案例,本文通過實例圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
springboot代碼,注解配置獲取yml,properties文件的map即鍵值對
這篇文章主要介紹了springboot代碼,注解配置獲取yml,properties文件的map即鍵值對,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
java poi設置生成的word的圖片為上下型環(huán)繞以及其位置的實現
這篇文章主要介紹了java poi設置生成的word的圖片為上下型環(huán)繞以及其位置的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09

