MyBatis-Plus里面的增刪改查詳解(化繁為簡)
一. MP 里面的增刪改查
在當前盛行的 SpringBoot 項目中,整合持久層這一塊,目前主流的有兩種:JPA 和 MyBatis-Plus。至于哪個用的更多一些,這個主要還是看每個公司的技術架構(gòu),但硬是要說一個最為常用的,我認為是 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 官網(wǎng)的例子,這里直接使用 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 官網(wǎng)提供的代碼生成模板也行。不管用哪種方法,最終要做的都是一樣的,就是把項目搭起來,實體類弄起來。
(2) 在這里,就直接使用 MP 官網(wǎng)提供的代碼模板吧。直接在 MP官網(wǎng) —— 指南 —— 代碼生成器 (新) 就能找到
(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 去調(diào)用
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) 其他就沒什么需要注意的,你想添加什么內(nèi)容,就往這個 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 就會幫我們?nèi)プ隽?,像這樣:
@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) 增和改其實本質(zhì)上是差不多的,運行成功之后,查看數(shù)據(jù)庫的結(jié)果就變成了這樣:
1.2.4 查
(1) 在 MP 中,查就更簡單了,因為在我們實際項目中用的最多的就是查詢了。當然往往我們的查詢會伴隨著很多條件,在 MP 中給我們提供了條件構(gòu)造器,也是能夠滿足到我們不寫 SQL 的場景的,這個后續(xù)再細聊。
(2) 對于單表的操作,在 MP 中就一個 list() 的方法就完成了
@GetMapping("/list") public List<User> list() { return userService.list(); }
(3) 通過 Postman 訪問接口后,在 IDEA 中可以看到 MP 中打印出來的日志
(4) 可能你會說,后面那些字段都沒有數(shù)據(jù),你不想去查出來,浪費資源,那應該怎么辦呢?這時就需要我們使用條件構(gòu)造器了,通過條件構(gòu)造器去進行操作
@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ù)庫上能夠?qū)?,否者查不出來的,很好理解,就和自己?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 小結(jié)
在 MP 中對單表的操作是非常方便的,如果對于需要連表的一對多或多對多,需要在對應的實體類上加一些注解啥的,具體還沒去研究過;因為個人覺得,在一些較為復雜的表結(jié)構(gòu)中,還不如自己寫 SQL 來的快。但是如果是對單表操作,強烈建議用 MP 自帶的方法,誰還寫 SQL 呢~
當然目前為止演示的都是很簡單的 CRUD,實際操作上肯定是不一樣的。因為在我們實際操作中,可能會頻繁的使用 MP 中的條件構(gòu)造器去根據(jù)業(yè)務不同來返回數(shù)據(jù)。這個會在后面繼續(xù)深入去演示一些 MP 中常用到的方法
另外需要說明一下的是,上述演示的代碼中,都是在 Controller層中進行的。我這里是為了方便,MP 中的 IService 中已經(jīng)有 CRUD 的方法了,就沒去到 service 層去操作。按照代碼的規(guī)范,還是更建議去到 service 層中處理業(yè)務邏輯的。
可能第三點會有些繞口,基礎好的可能明白我說的意思了,而至于基礎稍微沒那么好的,既然都看到這里了,我還是在簡單的演示一下標準版吧…比如要返回一個“用戶菜單”
(1) Controller
@Resource private IUserService userService; @GetMapping("/userMenus") public List<User> userMenus() { List<User> result = userService.userMenus(); //如果結(jié)果不為空,返回結(jié)果;否之返回 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…之類的),我這里直接放個圖片了,就不一步步演示了
或者類似這樣
總結(jié)
到此這篇關于MyBatis-Plus增刪改查的文章就介紹到這了,更多相關MyBatis-Plus增刪改查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Idea如何使用System.getenv()獲取環(huán)境變量的值
文章介紹了如何在Java中使用`System.getenv()`方法讀取環(huán)境變量的值,并提供了兩種配置環(huán)境變量的方法:啟動項配置和系統(tǒng)環(huán)境變量配置,對于系統(tǒng)環(huán)境變量,文章特別指出需要重啟電腦或程序才能使其生效2024-11-11Java數(shù)據(jù)結(jié)構(gòu)之簡單的連接點(link)實現(xiàn)方法示例
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之簡單的連接點(link)實現(xiàn)方法,涉及java指針指向節(jié)點的相關使用技巧,需要的朋友可以參考下2017-10-10Spring擴展之基于HandlerMapping實現(xiàn)接口灰度發(fā)布實例
這篇文章主要介紹了Spring擴展之基于HandlerMapping實現(xiàn)接口灰度發(fā)布實例,灰度發(fā)布是指在黑與白之間,能夠平滑過渡的一種發(fā)布方式,灰度發(fā)布可以保證整體系統(tǒng)的穩(wěn)定,在初始灰度的時候就可以發(fā)現(xiàn)、調(diào)整問題,以保證其影響度,需要的朋友可以參考下2023-08-08Mybatis-Plus處理Mysql?Json類型字段的詳細教程
這篇文章主要給大家介紹了關于Mybatis-Plus處理Mysql?Json類型字段的詳細教程,Mybatis-Plus可以很方便地處理JSON字段,在實體類中可以使用@JSONField注解來標記JSON字段,同時在mapper.xml中使用json函數(shù)來操作JSON字段,需要的朋友可以參考下2024-01-01