一、什么是MyBatis-plus?
MyBatis-plus是MyBatis的增強工具,在MyBatis基礎上只做增強不做改變,可以簡化基礎的CRUD操作(通過繼承?
BaseMapper
?接口可直接使用預定義的增刪改查方法)
二、MyBatis-plus快速入門
2.1 準備工作
2.1.1 數據庫數據準備
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;-- 使用數據庫
USE mybatis_test;-- 創建表[用戶表]
DROP TABLE IF EXISTS user_info;CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` 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' );
2.1.2 項目準備
1.創建SpringBoot項目;
2.添加MyBatis-plus和MySQL依賴,配置數據庫連接信息。
一、添加MyBatis-plus依賴(SpringBoot 3)和MySQL依賴
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version> </dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope> </dependency>
二、配置數據庫連接信息
# 數據庫連接配置 spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test? characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
2.2 代碼準備
?一、創建實體類UserInfo與表中字段對應
@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接口并繼承BaseMapper
@Mapper public interface UserInfoMapper extends BaseMapper<UserInfo> { }
查看BaseMapper,可以發現其中已經準備了各種基礎的SQL對應的方法:
這也就是為什么使用MyBatis-plus無需手動編寫SQL以及對應方法的原因。
2.3 CRUD單元測試
@SpringBootTest class DemoApplicationTests {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid selectById() {UserInfo userInfo = userInfoMapper.selectById(1);System.out.println(userInfo);}@Testvoid selectByIds() {List<UserInfo> userInfos = userInfoMapper.selectByIds(List.of(22,23,24));System.out.println(userInfos);}@Testvoid insert() {UserInfo userInfo = new UserInfo();userInfo.setUsername("王五");userInfo.setPhone("381200");userInfo.setGender(3);userInfo.setAge(19);userInfoMapper.insert(userInfo);}@Testvoid deleteById() {userInfoMapper.deleteById(1);}@Testvoid update() {UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setUsername("宮本");userInfoMapper.updateById(userInfo);}}
測試結果如下:
全部執行成功
三、MyBatis-plus復雜操作
?3.1 Mybatis-plus常見注解
在上面的代碼中,MyBatis是如何知道我們操作的是哪個表的?表中又有那些字段?觀察一下前面的Mapper接口:
BaseMapper指定了一個泛型,這個UserInfo就是與相應表對應的實體類,Mybatis-plus會根據實體類來推斷表的信息,默認情況下:
1.表名:由駝峰表示法轉換為蛇形表示法(如UserInfo->user_info)
2.字段名:也是駝峰表示法轉換為蛇形表示法(如deleteFlag->delete_flag)
3.主鍵:默認為id
當然,如果設計表時或編寫實體類時沒有按照標準定義類名/表名、屬性名/字段名,MyBatis-plus就無法正確推斷,此時就需要注解來標識類名對應的表名(或屬性名對應的字段名)
3.1.1 @TableName
@TableName用于標識類所對應的表名是什么
我們先將類名UserInfo改為Userinfo:
現在,再次測試selectByIds方法:
可以看到結果報錯了,提示userinfo這個表并不存在,可以看到由于命名的不規范導致MyBatis-plus無法正確推斷表名,接下來使用注解@TableName標識:
@Data @TableName("user_info")//告知MyBatis-plus這個類對應的是哪個表 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; }
再次測試selectByIds方法:
程序執行成功。
3.1.2 @TableField
?@TableName用于標識屬性所對應的字段名是什么
將屬性deleteFlag改為deleteflag:
測試insert方法:
報錯,提示字段deletefalg不存在,接下來,使用注解@TableFiled標識類中屬性對應的字段名:
@Data @TableName("user_info") public class Userinfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;//告知MyBatis-plus這個屬性對應的字段是什么@TableField("delete_flag")private Integer deleteflag;private Date createTime;private Date updateTime; }
再次測試:
執行成功。
3.1.3 @TableId
?@TableId用于標識表中主鍵對應的屬性是什么,一般將屬性名id作為主鍵,但是,如果將id修改為userId,MyBatis-plus就無法識別了,此時可以使用@TableId注解的value屬性標識主鍵,如:
測試方法和上面的兩個注解類似,這里就不再測試了,下面我們要介紹的是@TableId的另一個重要屬性——type:
我們先測試insert方法,往user_info中插入一個新數據并觀察:
可以看到,新插入的數據id是一個非常小的負數,這是因為
@TableId
注解的type
屬性默認值為IdType.ASSIGN_ID,
一般來說,主鍵默認為自增的,但是type屬性的默認值并不是自增,接下來,修改type屬性的值為IdType.AUTO:public class Userinfo {//將id設置為自增@TableId(type = IdType.AUTO)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; }
再次測試insert方法:
可以看到,修啊給type后,id正常自增
3.2 打印MyBatis-plus日志
?在配置文件中添加以下配置即可:
mybatis-plus:configuration: # 配置打印 MyBatis?志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.3 條件構造器(Wrapper)
前面只是使用MyBatis-plus進行一些簡單的CRUD操作,但是在實際應用中,可能還會在SQL語句中加入一些條件(如 id!=10 等),對于這種情況,MyBatis-plus為我們提供了一套強大的條件構造器(Wrapper),下面是主要的Wrapper類:
AbstractWrapper | ?個抽象基類,提供了所有Wrapper類共有的方法和屬性 |
---|---|
QueryWrapper | ?于構造查詢條件,在AbstractWrapper的基礎上拓展了?個select?法,允許指定查詢字段 |
UpdateWrapper | ?于構造更新條件,可以在更新數據時指定條件 |
LambdaQueryWrapper | 基于Lambda表達式的查詢條件構造器,它通過Lambda表達式來引用實體類的屬性,從而避免了硬編碼字段名 |
LambdaupdateWrapper | 基于Lambda表達式的更新條件構造器,它允許你使?Lambda表達式來指定更新字段和條件,同樣避免了硬編碼字段名的問題 |
3.3.1 QueryWrapper
?QueryWrapper只是一個條件構造器,并不是只能用于查詢語句,其它的刪除、更新語句也同樣可以使用。
一、查詢
使用構造器構造如下SQL:SELECT id,username,password,age FROM user_info WHERE age = 18 AND username "%min%"
在測試代碼中構造:
@Testvoid testQueryWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().select("id","username","age","password").eq("age",18).like("username","%min%");List<UserInfo> userInfos = userInfoMapper.selectList(queryWrapper);userInfos.forEach(System.out::println);}
二、更新
使用構造器構造如下SQL:
UPDATE user_info SET delete_flag=? WHERE age < 20
測試代碼:
@Testvoid testQueryWrapper2(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().lt("age",20);UserInfo userInfo = new UserInfo();userInfo.setDeleteFlag(0);userInfoMapper.update(userInfo,queryWrapper);}
三、刪除
使用構造器構造如下SQL:
DELETE FROM user_info WHERE age = 18
測試代碼:
@Testvoid testQueryWrapper3() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("age",18);userInfoMapper.delete(queryWrapper);}
在上面使用構造器的代碼中,涉及到一些縮寫的方法,這里列舉出常見的縮寫方法的含義:
? ? ? ?lt | “less than” 的縮寫,表示小于 |
---|---|
? ? ? ?le | “less than or equal to” 縮寫,表示小于或等于 |
? ? ? ?ge | “greater than or equal to”縮寫 ,表示大于或等于 |
? ? ? ?gt | “greater than”縮寫,表示大于 |
? ? ? ?eq | “equals”縮寫,表示等于 |
? ? ? ?ne | “not equals”縮寫,表示不等于 |
?
3.3.2 UpdateWrapper
對于更新語句,可以直接使用UpdateWrapper構造器進行構造,這要就不必創建對應的實體類(相較于QueryWrapper,多了一個set和setSql方法)
一、set方法
使用UpdateWrapper構造器構造如下SQL:
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
測試代碼:
@Testvoid testUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.set("delete_flag",0).in("id",List.of(1,2,3));userInfoMapper.update(updateWrapper);}
二、setSql方法(基于SQL更新)
@Testvoid testUpdateWrapper2(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.setSql("age = age + 10").eq("id",1);userInfoMapper.update(updateWrapper);}
3.3.3 LambdaQueryWrapper
?前面的QueryWrapper和UpdateWrapper都有一個共同特點,就是將字段名寫死了,如果后續字段名發生變化,這里也不會報錯,對此MyBatis-Plus 給我們提供了一種基于Lambda表達式的條件構造器,它通過 Lambda 表達式來引用實體類的屬性,從而避免了硬編碼字段名,也提高了代碼的可讀性和可維護性.
使用LambdaQueryWrapper構造以下SQL:
?UPDATE user_info SET delete_flag=? WHERE age < 20
測試代碼:
@Testvoid lambdaQueryWrapper(){LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();UserInfo userInfo = new UserInfo();userInfo.setDeleteFlag(0);lambdaQueryWrapper.in(UserInfo::getId,List.of(1,2,3));userInfoMapper.update(userInfo,lambdaQueryWrapper);}
3.3.4 LambdaUpdateWrapper
?使用LambdaUpdateWrapper構造以下SQL:
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
測試代碼:
?@Testvoid lambdaUpdateWrapper(){LambdaUpdateWrapper<UserInfo> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();lambdaUpdateWrapper.set(UserInfo::getDeleteFlag,5).set(UserInfo::getAge,5).in(UserInfo::getId,List.of(1,2,3));userInfoMapper.update(lambdaUpdateWrapper);}
3.4 自定義SQL
?對于更加復雜的查詢語句(如子查詢),可能無法直接使用條件構造器完成,因此,MyBatis-plus提供了自定義SQL的功能,可以利用Wrapper構造查詢條件,再結合Mapper編寫SQL
使用自定義SQL完成以下查詢:
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> selectUserInfoByCondition (@Param(Constants.WRAPPER) Wrapper<UserInfo> ew); }
測試代碼:
?@Testvoid selectUserInfoByCondition() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lt("age",20);userInfoMapper.selectUserInfoByCondition(queryWrapper).forEach(System.out::println);}
?使用自定義SQL,由幾個注意事項:
? 參數命名:在自定義 SQL 時, 傳遞 Wrapper 對象作為參數時, 參數名必須為 ew ,或者使用注解 @Param(Constants.WRAPPER) 明確指定參數為 Wrapper 對象.?
? 使用?${ew.customSqlSegment} :在 SQL 語句中,使用 ${ew.customSqlSegment} 來 引用 Wrapper 對象生成的 SQL 片段.?
? 不支持基于 entity 的 where 語句:自定義 SQL 時,Wrapper 對象不會基于實體類自動生成? where 子句,你需要手動編寫完整的 SQL 語句.