一、什么是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 语句.