Bootstrap

MyBatis Plus 项目的创建和使用

1. 快速上手

1.1. 项目的创建和配置

首先,创建一个 Spring Boot 工程,添加 MyBatis Plus 和 MySQL 对应的依赖,然后,和 MyBatis 一样,需要在 yml 文件中配置数据库连接信息

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
  <version>3.5.9</version>
</dependency>

创建好项目之后,需要根据数据库中的字段来写相应的实体类

@Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

MybatisPlus 提供了一个基础的 BaseMapper 接口,已经实现了单表的增删查改操作,自定义的 Mapper 只需要继承这个 BaseMapper,就不用自己实现相应的单表增删查改操作了


为了让 Spring 扫描到这个类,也是需要加上 @Mapper注解的,或者在启动类上加上@MapperScan注解,参数就写包的路径

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

1.2. 增删查改的简单演示

之后就可以进行增删查改的单元测试了

查询:

@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;

    //查询
    @Test
    void testSelect(){
        System.out.println(userInfoMapper.selectById(1));
    }
}

和使用 Mybatis 时的结果是一样的

那么就有一个问题,Mapper 中不写 sql 语句是怎么知道要操作哪张表的,其实就是继承的BaseMapper<UserInfo>中传入的泛型参数,会将 Java 中类的命名规范改为数据库中的命名规范,类中的属性也是按照规范映射到数据库中表的字段的,那么就会有一个问题,如果说类名或者属性名没有按照规范来定义,还能知道操作的是哪张表吗

把类名修改以后就报错了,报错信息为数据库中找不到这个表,如果命名规范的话是可以把UserInfo转化为表名user_info

这时候使用 @TableName来指定一下具体要操作哪张表就可以了

同理,属性名如果命名不规范也是不能自动转化成功的

把规范的驼峰命名方式修改一下就又报错了,这时候,就要使用@TableField注解来指定对应的表的字段

然后来看 insert 方法

@Test
void testInsert(){
    UserInfo userinfo = new UserInfo();
    userinfo.setUserName("java");
    userinfo.setPassword("java");
    userInfoMapper.insert(userinfo);
}

虽然说插入成功了,但是数据好像不太对,这里的 id 并没有按照自增的方式来增加,而且设置为了一个新的 id,原因就是没有指定数据库中的主键

通过@TableId注解可以设置 id 的一些属性,这里传入参数(type = IdType.AUTO)表示自增

再来看修改和删除操作

@Test
void testUpdate(){
    UserInfo userinfo = new UserInfo();
    userinfo.setId(3);
    userinfo.setPassword("00000");
    userInfoMapper.updateById(userinfo);
}
@Test
void testDelete(){
    userInfoMapper.deleteById(3);
}

这里演示的都是通过 id 来进行操作的,这里的 id 必须是对应实体类所映射表的主键

1.3. 日志打印

和 Mybatis 一样,也可以进行配置打印日志,来观察对应的 sql 语句

mybatis-plus:
  configuration: # 配置打印 MyBatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2. 条件构造器

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。

  1. AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。
  2. QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 andor 逻辑。
  3. UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
  4. LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
  5. LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

2.1. QueryWrapper

@Test
void testQueryWrapper() {
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("user_name", "password")
    .eq("delete_flag", 0)
    .like("user_name", "min");
    userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}

eq 就构造了一个相等条件,like 构造了一个模糊查询的条件,除此之外还有其他的一些模糊查询的构造

这就相当于下面的这条 sql 语句

部分方法名的表示含义:

方法名

表示

lt

"less than"的缩写,表示小于.

le

"less than or equal to"的缩写,表示小于等于

ge

"greater than or equal to"的缩写,表示大于等于.

gt

"greater than"的缩写,表示大于.

eq

"equals"的缩写,表示等于.

ne

"not equals"的缩写,表示不等于

如果要使用 delete 的话也是可以使用 QueryWrapper 来构造一个判断条件,然后再调用 delete 方法

2.2. UpdateWrapper

来看一下还用 QueryWrapper 来构造条件进行更新:

@Test
void testQueryWrapper2() {
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.lt("id", 2);
    UserInfo userInfo = new UserInfo();
    userInfo.setDeleteFlag(1);
    userInfoMapper.update(userInfo, queryWrapper);
}

还是先用 QueryWrapper 构造出判断条件,然后和要更新的对象传入 update 方法中,这样就有些麻烦了,来看使用 UpdateWrapper 来进行简化

@Test
void testUpdateWrapper() {
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("delete_flag", 0)
    .lt("id", 2);
    userInfoMapper.update(updateWrapper);
}

这里直接就可以构造出要更新的内容和判断条件,然后直接传入 update 方法中

再来看批量修改的方式:

@Test
void testUpdateWrapper1() {
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("delete_flag", 1)
    .in("id", List.of(1, 2, 3));
    userInfoMapper.update(updateWrapper);
}

这里通过 in 方法来构造 sql 语句中的 in

再来看涉及到表达式的 sql 语句怎么构造

@Test
void testUpdateWrapper2(){
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
    updateWrapper.setSql("age = age + 10")
    .in("id",List.of(1,2,3));
    userInfoMapper.update(updateWrapper);
}

可以直接通过 setSql 方法来设置 sql 语句

2.3. LambdaQueryWrapper

在上面的示例中,传入的参数都是字符串,也就是硬编码字段名,如果发生修改的话,不方便维护,写起来容易出错,就可以使用 LambdaQueryWrapper 来通过 lambda 表达式的方式来引用类的属性

@Test
void testLambdaQueryWrapper(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.lambda()
    .select(UserInfo :: getId,UserInfo :: getUserName,UserInfo :: getPassword)
    .eq(UserInfo::getId ,2);
    System.out.println(userInfoMapper.selectOne(queryWrapper));
}

直接使用就不用调用 lambda 方法了

@Test
void testLambdaQueryWrapper() {
    LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper
    .select(UserInfo::getId, UserInfo::getUserName, UserInfo::getPassword)
    .eq(UserInfo::getId, 2);
    System.out.println(userInfoMapper.selectOne(lambdaQueryWrapper));
}

通过这样的方式就避免了字符串容易写错的问题

2.4. LambdaUpdateWrapper

与之对应的,还有 LambdaUpdateWrapper,使用方法也是类似的

@Test
void testLambdaUpdateWrapper(){
    UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();
    updateWrapper.lambda()
    .set(UserInfo::getDeleteFlag, 0)
    .in(UserInfo::getId, List.of(1, 2, 3));
    userInfoMapper.update(updateWrapper);
}

也是直接使用,就不用调用 lambda 方法了

@Test
void testLambdaUpdateWrapper() {
    LambdaUpdateWrapper<UserInfo> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
    lambdaUpdateWrapper
    .set(UserInfo::getDeleteFlag, 1)
    .in(UserInfo::getId, List.of(1, 2, 3));
    userInfoMapper.update(lambdaUpdateWrapper);
}

3. 自定义 sql

Mybatis plus 提供的方法可能不能满足一些其他需求,这是就可以自定义 sql,第一种实现方式还是之前 Mybatis 的写法,直接把 sql 语句写在注解里,或者是使用 XML 的方式

除此之外,Mybatis plus 也提供了另一种构造自定义 sql 的方式,来看官方文档中的介绍

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    @Select("select * from user_info ${ew.customSqlSegment}")
    List<UserInfo> selectByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
}

通过 ${ew.customSqlSegment} 引入了 Wrapper 对象生成的 SQL 片段,来实现自定义 sql,然后调用方法,传入一个 Wrapper 对象

XML 方式也是一样的,把注解中的 sql 语句写到 XML 中就可以了

再来看上面 sql 表达式的例子

来自定义一下上面的 sql 语句

@Update("update user_info set age = age + #{age} ${ew.customSqlSegment}")
Integer updateByCustom(@Param("age") Integer age,@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
@Test
void updateByCustom() {
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.in("in",List.of(1,2,3));
    userInfoMapper.updateByCustom(10,queryWrapper);
}

 主页

;