MyBatis-Plus快速入门
MyBatis-Plus简介:
MyBatis-Plus是MyBatis的超集,它只是在MyBatis的基础上添加了一些新的功能,MyBatis原有的功能并没有改变,可以用更少的代码实现数据库的CRUD(增删改查),让开发更简洁。
CRUD功能实现
准备工作:
首先创建一张用户表和一张图书表
然后添加MyBatis-Plus和Mysql依赖。
SpringBoot3:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
MySql:
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
配置数据库:
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?
characterEncoding=utf8&useSSL=false
#连接数据库的⽤⼾名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=521314
创建实体类:
@Data
public class UserInfo {
private Integer id;
private String username;
private String password;
private Integer age;
private String gender;
private String phone;
private Integer deleteFlag;
private String createTime;
private String updateTime;
}
编写Mapper接口类:
由于MyBatis-Plus提供了一个基础的BaseMapper接口,已经实现了单表的CRUD,我们自己定义的Mapper接口只要继承BaseMapper就无需自己实现单表CRUD了。
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
也可以在启动类上加上@MapperScan,扫描Mapper文件夹,二者选其一即可。
写几个测试试试:
@SpringBootTest
class MyBatisPlusApplicationTests {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void testInsert() {
UserInfo user = new UserInfo();
user.setUsername("bite");
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 testUpdateById() {
UserInfo user = new UserInfo();
user.setId(1);
user.setPassword("4444444");
userInfoMapper.updateById(user);
}
}
运行结果为:
同时数据库信息也被同时修改了:
常见注解
MyBatis-Plus是如何知道我们要操作的是哪张表,要操作哪些字段呢?
首先Mapper接口在继承BaseMapper时指定了一个泛型<UserInfo>,这个UserInfo就是与数据库表相对应的实体类。
MyBatis-Plus会根据这个实体类来推断表的信息。
一般情况下:
1.表名:实体类的驼峰表示法转换为蛇形表示法。例如:UserInfo->user_info
2.字段:根据实体类的属性名转换为蛇形表示法作为字段名,比如:deleteFlag->delete_flag
3.主键:默认为id。
如果实体类和数据库不是按照上述规则定义的话,MyBatis-Plus也给我们提供一些注解来让我们标识标的信息。
1.@TableName
将UserInfo修改为Userinfo,按照规则无法找到对应的表:
通过@TableName来标识实体类对应的表:
@Data
@TableName("user_info")
public class Userinfo {
private Integer id;
private String username;
private String password;
private Integer age;
private String gender;
private String phone;
private Integer deleteFlag;
private String createTime;
private String updateTime;
}
重新运行,结果正常。
2.@TableField
和@TableName类似,@TableField是用来修饰对应的字段名的。
将deleteFlag修改为deleteflag,重新执行测试方法。
这时我们使用@TableFiled来标识对应的字段名:
@Data
@TableName("user_info")
public class Userinfo {
private Integer id;
private String username;
private String password;
private Integer age;
private String gender;
private String phone;
@TableField("delete_flag")
private Integer deleteflag;
private String createTime;
private String updateTime;
}
运行结果如下:
3.@TableId
修改属性名id为userId,重新执行测试方法:
使用@TableId来指定对应的主键:
@Data
@TableName("user_info")
public class Userinfo {
@TableId("id")
private Integer userId;
private String username;
private String password;
private Integer age;
private String gender;
private String phone;
@TableField("delete_flag")
private Integer deleteflag;
private String createTime;
private String updateTime;
}
如果属性名和字段名不一致,需要在@TableId指定对应的字段名;
属性名和字段名一致,直接加@TableId注解就可以。
日志打印
借助日志,我们可以查看MyBatis-Plus执行的SQL语句,参数和结果,
配置文件如下:
mybatis-plus:
configuration: # 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
条件构造器
MyBatis-Plus提供了一套强大的条件构造器(Wapper),用于构造复杂的数据库查询条件,Wapper类允许使用链式调动的方式构造条件,无需编写繁琐的SQL语句,从而提高效率并减少SQL注入的风险。
以下是主要的Wappper类及其主要功能:
AbstractWrapper:这是一个抽象基类,提供了所有的Wrapper类共有的方法和属性。
QueryWrapper:用于构造查询条件,在AbstractWrapper的基础上拓展了一个select方法,允许指定查询字段。
UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。
LambdaQueryWrapper:基于Lambda表达式的查询条件构造器,它通过Lambda表达式来引用实体类的属性,从而避免了硬编码字段名的问题。
以下是使用方法:
1.QueryWrapper
查询:
sql语句:
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username
"%min%"
测试代码:
@Test
void testQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.select("id","username","password","age")
.eq("age",18)
.like("username","min");
List<UserInfo> list = userInfoMapper.selectList(userInfoQueryWrapper);
list.forEach(System.out::println);
}
运行结果:
更新:
sql语句:
UPDATE user_info SET delete_flag=? WHERE age < 20
测试代码:
void testUpdateByQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.lt("age",20);
UserInfo userInfo = new UserInfo();
userInfo.setDeleteflag(1);
userInfoMapper.update(userInfo,userInfoQueryWrapper);
}
运行结果:
lt:“less than”的缩写,表示小于。
le:“less than or equal to”的缩写,表示小于等于。
ge:“greater than or equal to”的缩写,表示大于等于。
gt:“greater than”的缩写,表示大于。
eq:“equals”的缩写,表示等于。
ne:“not equals”的缩写,表示不等于。
删除:
sql语句:DELETE FROM user_info where age = 18
测试代码:
@Test
void testDeleteByQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.eq("age",18);
userInfoMapper.delete(userInfoQueryWrapper);
}
运行结果:
2.UpdateWrapper
对于更新,UpdateWrapper可以在不创建实体对象的情况下,直接设置更新字段和条件。
sql语句:
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
测试代码:
void testUpdateByUpdateWrapper(){
UpdateWrapper<UserInfo> userInfoUpdateWrapper = new UpdateWrapper<UserInfo>()
.set("delete_flag",0)
.set("age",5)
.in("id",List.of(1,2,3));
userInfoMapper.update(userInfoUpdateWrapper);
}
运行结果:
3.LambdaQueryWrapper和LambdaUpdateWrapper
上述的条件构造器都存在一个问题,就是需要写死字段名,如果字段名发生改变,可能会因为测试不到位酿成事故。
而LambdaQueryWrapper和LambdaUpdateWrapper就可以通过lambda表达式来引用实体类的属性,从而避免了硬编码字段名。
具体使用:
LambdaQueryWrapper
@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).forEach(System.out::println);
}
LambdaUpdateWrapper
void testLambdaUpdateWrapper(){
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);
}