MyBatis-Plus里面的增刪改查詳解(化繁為簡)
一. MP 里面的增刪改查
在當前盛行的 SpringBoot 項目中,整合持久層這一塊,目前主流的有兩種:JPA 和 MyBatis-Plus。至于哪個用的更多一些,這個主要還是看每個公司的技術架構,但硬是要說一個最為常用的,我認為是 MyBatis-Plus,而在這里也是對 MyBatis-Plus 的一個使用進行演示
好了,廢話不多說,直接開始吧。為了減少冗余,下面所有 MyBatis-Plus 都使用 MP 來代替
1.1 項目搭建
項目的創(chuàng)建就直接跳過了,直接從依賴開始吧。開始之前得先弄個表,表怎么弄都行,下面這個是我測試建的,可以參考一下
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶名', `age` int(0) NOT NULL COMMENT '年齡', `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '手機號', `email` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '郵箱', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '創(chuàng)建時間', `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '創(chuàng)建人', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更改時間', `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更改人', `is_delete` int(0) NULL DEFAULT NULL COMMENT '是否刪除 0-未刪除 1-已刪除', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3554031 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用戶表' ROW_FORMAT = Dynamic;
依賴
(1) 目前 MP 的最新版本
<!-- Mybatis-plus 依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>(2) 當然,如果你想使用 MP 中的快速生成實體類,需要添加 MP 中的一個工具依賴且需導入一個模板引擎的依賴 (模板可以自定義,具體看 MP 官網的例子,這里直接使用 Freemark)
<!-- Mybatis-plus 逆向自動生成實體類所需依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>(3) 以上的都是 MP 中所需的依賴,除此之外,當然還少不了 SpringWeb 的依賴了;我們還需要對數(shù)據(jù)庫進行操作,MySQL 的依賴也必不可缺
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>逆向工程創(chuàng)建實體類
(1) 其實這個有好幾種方法,自己手動創(chuàng)建也行;使用 IDEA 中的一些插件也行;或者使用 MP 官網提供的代碼生成模板也行。不管用哪種方法,最終要做的都是一樣的,就是把項目搭起來,實體類弄起來。
(2) 在這里,就直接使用 MP 官網提供的代碼模板吧。直接在 MP官網 —— 指南 —— 代碼生成器 (新) 就能找到

(3) copy 這段代碼到 maven 工程自帶的單元測試中,然后根據(jù)注釋去修改一下,直接運行即可。
(4) 稍微解釋一下怎么使用這個,其實很簡單:
- url 、username 、password :即你數(shù)據(jù)庫連接的地址、用戶名、密碼
- outputDir :這個就是注釋的意思,輸出目錄嘛~但注意一下,這個寫到 java 目錄即可。(可參考:“D:\code\test\test-demo\ts-mybatis\src\main\java”)
- parent :父包名 (一般是 com.xxx)
- moduleName :父包名下的模塊名 (即 com.xxx.yyy 這個 yyy 即是這個模塊名了)
- pathInfo :后面的那個地址即是 mapperxml 的路徑了 (可參考:“D:\code\test\test-demo\ts-mybatis\src\main\resources\mapper”)
- addInclude :這個就更簡單了,你要它幫你生成什么實體類,你就把表名往這這里填,注意的是,名字可別寫錯,不然識別不出來
- addTablePrefix :這個就是一些表的前綴在生成到 Java 代碼中的類名時,給你去掉前綴,沒有可以不管他
/**
* mp 逆向工程生成實體類
*/
@Test
void contextLoads() {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/ts_mybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=Asia/Shanghai", "root", "root")
.globalConfig(builder -> {
builder.author("Peng") // 設置作者
.enableSwagger() // 開啟 swagger 模式
.fileOverride() // 覆蓋已生成文件
.outputDir("D:\\code\\test\\test-demo\\ts-mybatis\\src\\main\\java"); // 指定輸出目錄
})
.packageConfig(builder -> {
builder.parent("com.peng") // 設置父包名
.moduleName("tsmybatis") // 設置父包模塊名
.pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\code\\test\\test-demo\\ts-mybatis\\src\\main\\resources\\mapper")); // 設置mapperXml生成路徑
})
.strategyConfig(builder -> {
builder.addInclude("user") // 設置需要生成的表名
.addTablePrefix("t_", "c_"); // 設置過濾表前綴
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默認的是Velocity引擎模板
.execute();
}(5) 注意,這個如果沒有加 模板引擎 運行的時候會報錯,加上 Freemarker 依賴即可
大功告成之后,在你的項目中 MP 就會把整個項目基礎模塊都給搭好了,如下圖:

注意,mapper 里面的掃描在 MP 中并不會幫你生成,所以這個 MapperScan 還需要自己去加上,在啟動類上面加上一個 @MapperScan 這個注解,去掃描你的 mapper 文件
@MapperScan(value = {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->"com.peng.tsmybatis.mapper"})1.2 極其便利的單表操作
以下的測試都是,都是使用 Postman 進行測試的,在這里為了方便測試,全都是使用 GetMapping 去調用
1.2.1 增
@Resource
IUserService userService;
@GetMapping("/add")
public boolean add() {
User user = new User();
user.setName("李四");
user.setAge(18);
return userService.save(user);
}
(1) 很簡單,其實就是 new 了一個對象扔到 MP 的方法里面而已,通過觀察 IUserService 這個接口可以發(fā)現(xiàn),它繼承了 IService<User> 且泛型里面放的就是你對應的實體類 User,因此在此 service 下的一切 MP 相關的方法都是針對 User 這個實體類的操作
(2) 因為 User 這個實體類是對應數(shù)據(jù)庫中的 User 表的,所以需要注意的是當前的這個表設計中是否有哪些必填的字段,如果遺漏了(即沒有 set 那個值到這個 User 對象中),那么就會報錯
(3) 其他就沒什么需要注意的,你想添加什么內容,就往這個 User 對象中 set 什么進去就可以了。成功即返回 true 了,反之則 false 了。另外如果你想查看 MP 幫你執(zhí)行的 SQL 可以在 yaml 或者 properties 中加上以下這段。我這里使用的是 yaml 文件配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印 mybatis-plus 的執(zhí)行日志添加之后訪問接口時便會有以下日志打?。?/p>

(4) 我這里使用的是 Postman 來測試這個接口,返回 true 則表示成功了,此時去數(shù)據(jù)庫查看便可發(fā)現(xiàn),多了一條 name = 李四;age = 18 的記錄

1.2.2 批增
(1) 當我們有當量添加的需求時,不停的去 new 對象太麻煩了,因此 MP 為我們提供了批量添加的方法。
(2) 還是很簡單,只是由原來的一個對象變成了集合而已。我們只需要把需要添加的信息,收集成一個集合即可,然后把這個集合丟給 MP ,剩下的事情 MP 就會幫我們去做了,像這樣:
@GetMapping("/addBatch")
public boolean addBatch() {
List<User> entityList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
User user = new User();
user.setName("張三" + i);
user.setAge(20 + i);
entityList.add(user);
}
return userService.saveBatch(entityList);
}(3) 通過 Postman 訪問 http://localhost:8082/addBatch 這個接口后返回 true,表示成功了,此時查看數(shù)據(jù)庫就多了10條數(shù)據(jù):

(4) 玩法很簡單,只是從一個對象,變成了一個集合而已。所以 MP 還是很方便的,它在原來的 MyBatis 上增加了很多對數(shù)據(jù)庫的操作方法,這些都只是它最基礎的一些操作。
1.2.3 改、批改
(1) 這個與增其實是一樣的,唯一的區(qū)別是需要傳一個 ID,不然 MP 不知道你需要對哪條記錄進行修改。所以只需要在上面的基礎上多去 set 一個 id 就可以了,像這樣:
@GetMapping("/update")
public boolean update() {
User entity = new User();
entity.setId(1);
entity.setName("靈兒");
entity.setAge(16);
return userService.updateById(entity);
}
@GetMapping("/updateBatch")
public boolean updateBatch() {
List<User> entityList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
User user = new User();
user.setId(i + 1);
user.setName("拜月" + i);
user.setAge(30 + i);
entityList.add(user);
}
return userService.updateBatchById(entityList);
}(2) 增和改其實本質上是差不多的,運行成功之后,查看數(shù)據(jù)庫的結果就變成了這樣:

1.2.4 查
(1) 在 MP 中,查就更簡單了,因為在我們實際項目中用的最多的就是查詢了。當然往往我們的查詢會伴隨著很多條件,在 MP 中給我們提供了條件構造器,也是能夠滿足到我們不寫 SQL 的場景的,這個后續(xù)再細聊。
(2) 對于單表的操作,在 MP 中就一個 list() 的方法就完成了
@GetMapping("/list")
public List<User> list() {
return userService.list();
}(3) 通過 Postman 訪問接口后,在 IDEA 中可以看到 MP 中打印出來的日志

(4) 可能你會說,后面那些字段都沒有數(shù)據(jù),你不想去查出來,浪費資源,那應該怎么辦呢?這時就需要我們使用條件構造器了,通過條件構造器去進行操作
@GetMapping("/list")
public List<User> list() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("id","name","age");
// qw.lambda().select(User::getId, User::getName, User::getAge); JDK8的方法
return userService.list(qw);
}
(5) 注意,括號里面的字符串需要與你數(shù)據(jù)庫上能夠對應上,否者查不出來的,很好理解,就和自己寫 SQL 一樣,如果查詢的字段表中沒有,顯然也是查不出來的,MP 只是幫我們把 SQL 給寫了而已
12.5 刪、批刪
(1) 這個其實和修改類似的,也是需要傳一個 ID ,不然 MP 不知道你要刪除的是哪一條數(shù)據(jù)。
(2) 還是一樣,刪除單條記錄,只需要 new 一個對象然后傳一個你要刪除的 ID 進去,MP 就會幫你處理了;而批刪的話則是一個集合了,也是需要傳 ID 的
@GetMapping("/delete")
public Boolean delete() {
User entity = new User();
entity.setId(1);
return userService.removeById(entity);
}
@GetMapping("/deleteBatch")
public boolean deleteBatch() {
List<User> entityList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
User user = new User();
user.setId(i + 1);
entityList.add(user);
}
return userService.removeBatchByIds(entityList);
}(3) 與修改稍微有點不一樣的是,你不需要傳修改的值過去了,只需要傳你要刪除的 ID 即可。
(4) 需要注意的是,MP 的這個方法是物理刪除的。而在我們實際開發(fā)中,有些業(yè)務場景是邏輯刪除的,也就是說我們的表中有一個類似 is_delete 的字段,刪除時只需要修改這個字段由 0 變 1或是由 1 變 0 即可,具體看實際需求。
(5) 在 MP 中同樣也封裝了邏輯刪除的一些配置,當你業(yè)務是邏輯刪除時,可以在 IDEA 中這樣去配置,告訴 MP 我這里使用的是邏輯刪除,別真把我的記錄給刪除掉了~很簡單,只需要在邏輯刪除的字段上加一個注解就可以搞定
@TableLogic(value = "0",delval = "1")
private Integer isDelete;(6) @TableLogic() 就是這個注解,可以去下載 MP 源碼查看:第一個參數(shù)是未刪除的值,第二個參數(shù)是已刪除的值,這里就不放圖片了,感興趣的朋友可以點進去瞅瞅。
(7) 除了這種配置方式外,還可以在 application.yaml 或者 application.properties 那些配置文件中進行配置,就是說,當你有好多個實體類,而好多個實體類都是邏輯刪除,那么也就意味著每一個注解里面的參數(shù)都要寫上 value = “0”,delval = “1” 這樣一段,顯然過于冗余。所以我們可以在配置文件中進行一個全局配置,像這樣:
mybatis-plus:
global-config:
db-config:
logic-delete-field: 1 #刪除
logic-not-delete-value: 0 #未刪除(8) 加了這個之后,MP 就會對你當前的實體類所對應的表的 CRUD 操作都是帶上邏輯刪除的一個邏輯,也就是 is_delete=0 ,就是當前記錄是未刪除的。
(9) 如果在前面開啟了 MP 的執(zhí)行日志就會發(fā)現(xiàn),MP 在執(zhí)行 CRUD 的時候,最后都加上了一個 WHERE is_delete=0 的一個判斷
1.3 一些小擴展
(1) 一般而言,我們設計表的時候,有一些字段是往往都是亙古不變的,像類似 create_time、update_time 那些,像我們當前的這個表:

(2) 像剛剛提到的兩個字段,在我們每一次添加或者修改的時候都需要去更新一下時間,一個兩個還好,如果多起來的話就會發(fā)現(xiàn)好多代碼都是重復的,特別冗余。對此 MP 給我提供了解決方案,可以在進行插入、修改的時候就自動幫我們進行一個處理了
(3) 也和上面處理邏輯刪除一樣,一個注解就完事了,但這個需要去配置一下,創(chuàng)建一個配置類,實現(xiàn) MetaObjectHandler 這個接口,重寫他的兩個方法就可以了,如下
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
/*
參數(shù)一: 屬性的名稱
參數(shù)二: 你想給這個屬性設置的值
參數(shù)三: 元對象,所有入?yún)⒌?MetaObject 必定是 entity 或其子類的 MetaObject
*/
this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
this.setFieldValByName("isDelete", 0, metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
}
}(4) 寫好配置類之后,在實體類上使用 @TableField() 這個注解和這個配置類呼應上就可以了,像這樣
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Integer isDelete;
(5) 這里的意思就是說:當進行 INSERT 操作的時候,自動幫我 createTime、updateTime 字段都設置成當前時間,而 isDelete 則默認設置成 0;當 UPDATE 的時候,只更改 updateTime 的時候改成當前更改的時間
(6) 實踐才是檢驗真理的唯一標準,咱們來試一下。我這里為了省事,就不用 Postman 去發(fā)請求訪問接口了,直接在單元測試中進行
@Resource
private UserMapper userMapper;
@Test
public void test08() {
User user = new User();
user.setName("伏羲");
user.setAge(131);
int result = userMapper.insert(user);
System.out.println(result == 1 ? "添加成功" : "添加失敗");
}從控制臺打印的日志可以看到,create_time, update_time, is_delete 這三個值 MP 默認幫我去添加了數(shù)據(jù),而添加的數(shù)據(jù)正是我們在配置文件上設置的

(7) UPDATE 也是一樣的,這里就不演示了
1.4 小結
在 MP 中對單表的操作是非常方便的,如果對于需要連表的一對多或多對多,需要在對應的實體類上加一些注解啥的,具體還沒去研究過;因為個人覺得,在一些較為復雜的表結構中,還不如自己寫 SQL 來的快。但是如果是對單表操作,強烈建議用 MP 自帶的方法,誰還寫 SQL 呢~
當然目前為止演示的都是很簡單的 CRUD,實際操作上肯定是不一樣的。因為在我們實際操作中,可能會頻繁的使用 MP 中的條件構造器去根據(jù)業(yè)務不同來返回數(shù)據(jù)。這個會在后面繼續(xù)深入去演示一些 MP 中常用到的方法
另外需要說明一下的是,上述演示的代碼中,都是在 Controller層中進行的。我這里是為了方便,MP 中的 IService 中已經有 CRUD 的方法了,就沒去到 service 層去操作。按照代碼的規(guī)范,還是更建議去到 service 層中處理業(yè)務邏輯的。
可能第三點會有些繞口,基礎好的可能明白我說的意思了,而至于基礎稍微沒那么好的,既然都看到這里了,我還是在簡單的演示一下標準版吧…比如要返回一個“用戶菜單”
(1) Controller
@Resource
private IUserService userService;
@GetMapping("/userMenus")
public List<User> userMenus() {
List<User> result = userService.userMenus();
//如果結果不為空,返回結果;否之返回 null
return ObjectUtils.isNotEmpty(result) ? result : null;
}(2) Service,注入一個 Mapper,其中也有 MP 自帶的方法。正常來說,上面演示的都應該在這里,也就是 Service 層進行處理,再返回到 Controller 中
@Autowired
private UserMapper userMapper;
@Override
public List<User> userMenus() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.lambda().select(User::getId, User::getName, User::getAge);
return userMapper.selectList(qw);
}(3) 如果需要寫 SQL ,那么也是一樣的,只是跳到 Mapper 這個接口,然后再跳到 MapperXML 中去寫而已,當然你也可以在 Mapper 時使用一些 MyBatis 的注解(@Select、@Update…之類的),我這里直接放個圖片了,就不一步步演示了

或者類似這樣

總結
到此這篇關于MyBatis-Plus增刪改查的文章就介紹到這了,更多相關MyBatis-Plus增刪改查內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java利用Spire.Doc for Java實現(xiàn)Word轉 PCL打印格式
在日常的企業(yè)級開發(fā)中,文檔處理是一個繞不開的話題,本文將介紹如何在 Java 后端環(huán)境中,利用 Spire.Doc for Java 庫,在不依賴 Microsoft Office 軟件的情況下,實現(xiàn) Word 文檔到 PCL 格式的轉換,感興趣的可以了解下2026-04-04
Mybatis日志參數(shù)快速替換占位符工具的詳細步驟
這篇文章主要介紹了Mybatis日志參數(shù)快速替換占位符工具的詳細步驟,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
解決java.util.NoSuchElementException異常的問題
這篇文章主要介紹了解決java.util.NoSuchElementException異常的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
SpringBoot整合DeepSeek實現(xiàn)AI對話功能
本文介紹了如何在SpringBoot項目中整合DeepSeek API和本地私有化部署DeepSeekR1模型,通過SpringAI框架簡化了人工智能模型的集成,感興趣的小伙伴跟著小編一起來看看吧2025-02-02

