Mybatis-Plus相关使用

目录

1.快速开始

1.1 导入依赖

1.2 创建Mapper

1.3 增加 @MapperScan扫描注解

1.4 测试CRUD

2.常见注解

@TableName

@TableId

 @TableField

4.核心功能

4.1 条件构造器

4.1.1 QueryWrapper

4.1.2 UpdateWrapper

LambdaQueryWrapper和LambdaUpdateWrapper

条件查询:

in:设置单个字段的 IN 条件,即字段的值在给定的集合中

NULL值处理

if语句控制条件追加

查询投影

逻辑删除

4.2 自定义SQL

4.2.1 基本使用

4.2.2 多表联查

普通实现

Wrapper构建查询条件实现


完整教程资料icon-default.png?t=N7T8https://juejin.cn/post/7010012164731699207

学习资料icon-default.png?t=N7T8https://htmlpreview.github.io/?https://github.com/caolib/note/blob/master/mybatis-plus.htmlMyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1.快速开始

1.1 导入依赖

导入mybatis-plus依赖,包含了mybatis,不用额外再导入mybatis依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

 application.yml配置mysql数据源

# DataSource Config
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost/mp_plus?serverTimezone=GMT%2B8&characterEncoding=UTF-8&allowMultiQueries=true
    username: root
    password: 123456

1.2 创建Mapper

为了简化单表CRUD,mp已经提供了对于单表的CRUD操作的接口BaseMapper,直接继承BaseMapper接口即可直接使用

// 在对应的Mapper上面继承基本的类 BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
	// 所有的CRUD操作都已经编写完成了
}

1.3 增加 @MapperScan扫描注解

@MapperScan("com.mpstudy.mp.mapper")

1.4 测试CRUD

测试BaseMapper中对单表CRUD操作 (基本是基于主键实现的CRUD操作)

///selectBatchIds接受的是一个list
categoryDao.selectBatchIds(req.getCategory2())
                        .stream()
                        .map(AurrCategory::getName)
                        .collect(Collectors.toList())

@Test
public void testInsert() {
    User user = new User();
    //user.setId(5L);
    user.setUsername("ikun23");
    user.setPassword("123");
    user.setPhone("18688990011");
    user.setBalance(200);
    user.setInfo(UserInfo.of(24,"英语老师","female"));
    user.setCreateTime(LocalDateTime.now());
    user.setUpdateTime(LocalDateTime.now());
    userMapper.insert(user);
}

@Test
public void testSelectById() {
    User user = userMapper.selectById(4L);
    System.out.println(user);
}

@Test
public void testSelectByIds() {
    selectBatchIds接受的是一个list
    List<User> users = userMapper.selectBatchIds(List.of(1, 2, 3));
    users.forEach(System.out::println);
}


@Test
public void testUpdate() {
    User user = new User();
    user.setId(5L);
    user.setBalance(3);
    user.setInfo(UserInfo.of(24,"英语老师","female"));
    user.setCreateTime(LocalDateTime.now());
    user.setUpdateTime(LocalDateTime.now());

    userMapper.updateById(user);
}

@Test
public void testDelete() {
    System.out.println(userMapper.deleteById(5L));
}

总结:只要继承了BaseMapper,就能直接对单表进行CRUD操作

2.常见注解

问题:在刚刚的测试中,我们直接调用BaseMapper中的方法就能对表增删改查,在继承BaseMapper的时候我们只是指定了一个泛型<User>,并没有指定是哪张表,那么mybatis-plus怎么知道我们要操作的是user表呢?它又是怎么知道这张表中的所有字段名呢?

解答:其实mp遵从约定大于配置的思想,mp从User推导出数据库中表名为user,然后根据User类中的所有变量名从驼峰命名转成下划线作为数据库的字段名,从而在调用方法时可以自动生成正确的sql语句。

如果我们在创建User类和user表的时候遵从驼峰命名和下划线命名,那么我们不需要做额外的配置,如果类名和表名、属性名和字段名直接不是简单的转换,那么我们就不得不使用一些相应的注解来声明表的信息

@TableName

  • 描述:表名注解,标识实体类对应的表

  • 使用位置:实体类

@Data   //lombok注解
@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

@TableId

  • 描述:主键注解

  • 使用位置:实体类主键字段

@TableName("sys_user")
public class User {
    @TableId(type = IdType.AUTO) //自增
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
属性类型必须指定默认值描述
valueString""主键字段名
typeEnumIdType.NONE指定主键类型

IdType支持的类型:

描述
AUTO数据库 ID 自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert 前自行 set 主键值
ASSIGN_ID分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
ID_WORKER分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
UUID32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

常见的id设计:

  • AUTO:利用数据库的id自增长

  • INPUT:手动生成id

  • ASSIGN_ID雪花算法生成Long类型的全局唯一id,这是默认的ID策略

 @TableField

  • 描述:字段注解(非主键),映射到数据库中的字段

@TableName("sys_user")
public class User {
    @TableId
    private Long id;

    @TableField("nickname")
    private String name;

    @TableField(value = "confirm_time")
    private LocalDateTime confirmTime;

    @TableField(value = "create_time", updateStrategy = FieldStrategy.NEVER)
    private LocalDateTime createTime;

    @TableField(value = "update_time", updateStrategy = FieldStrategy.NEVER)
    private LocalDateTime updateTime;

}

4.核心功能

4.1 条件构造器

条件构造器 | MyBatis-Plusicon-default.png?t=N7T8https://baomidou.com/guides/wrapper/除了新增以外,修改、删除、查询的SQL语句都需要指定where条件。因此BaseMapper中提供的相关方法除了以id作为where条件以外,还支持更加复杂的where条件。

4.1.1 QueryWrapper

查询:查询名字带有o,且存款大于等于1000的人


select id,username,info,balance 
from user
where username like %o% and balance >= 1000;
@Test
public void test02() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //构建查询条件
    wrapper.select("id", "username", "info", "balance")
        .like("username", "o")
        .ge("balance", 1000);
    //查询数据
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}

4.1.2 UpdateWrapper

基于BaseMapper中的update方法更新时只能直接赋值,对于一些复杂的需求就难以实现。 例如:更新id为1,2,4的用户的余额,扣200,对于的SQL应该是:

UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)

SET的赋值结果是基于字段现有值的,这个时候就要利用UpdateWrapper中的setSql功能了:

@Test
void testUpdateWrapper() {
    List<Long> ids = List.of(1L, 2L, 4L);
    // 1.生成SQL
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            .setSql("balance = balance - 200") // SET balance = balance - 200
            .in("id", ids); // WHERE id in (1, 2, 4)
    // 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,
    // 而是基于UpdateWrapper中的setSQL来更新
    userMapper.update(null, wrapper);
}

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,可能会出现字符串写错的现象,因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:

LambdaQueryWrapper和LambdaUpdateWrapper

  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。

  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。


select id,username,info,balance 
from user
where username like %o% and balance >= 1000;
@Test
public void test02() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    //构建查询条件
    //由原来的字符串变成getter函数对象获取类属性
    wrapper.select(User::getId, User::getUsername, User::getInfo, User::getBalance)
        .like(User::getUsername, "o")
        .ge(User::getBalance, 1000);
    userMapper.selectList(wrapper);
}

条件查询:

lt: 小于(<) less,   gt:大于(>) great,     eq:等于(=)

or()就相当于我们sql语句中的or关键字,不加默认是and

lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);

----> 
SELECT id,name,password,age,tel FROM user WHERE (age < ? OR age > ?)

 

in:设置单个字段的 IN 条件,即字段的值在给定的集合中

NULL值处理

if语句控制条件追加
方法1、
Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
if(minAge!=null){
    lqw.gt(User::getAge, minAge);
}
if(maxAge!=null){
    lqw.lt(User::getAge, maxAge);
}
List<User> userList = userDao.selectList(lqw);
userList.forEach(System.out::println);


方法2、

Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//参数1:如果表达式为true,那么查询才使用该条件
lqw.gt(minAge !=null , User::getAge, minAge)
   .lt(maxAge !=null , User::getAge, maxAge);
List<User> userList  = userDao.selectList(lqw);
userList.forEach(System.out::println);

查询投影

不查询所有字段,只查询出指定内容的数据

最终的sql语句为:SELECT id,name,age,tel FROM user

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.select(User::getId,User::getName,User::getAge);
或则
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("id","name","age","tel");     
  • 聚合与分组查询,无法使用lambda表达式来完成

逻辑删除

逻辑删除支持 | MyBatis-Plusicon-default.png?t=N7T8https://baomidou.com/guides/logic-delete/

4.2 自定义SQL

4.2.1 基本使用

MybatisPlus提供了自定义SQL功能,可以让我们利用Wrapper生成查询条件,再结合Mapper.xml或注解编写SQL

UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)

update user set balance = balance - 200使用注解完成

//将wrapper作为ew,并使用ew.customSqlSegment取出条件是固定写法


@Update("update tb_user set balance = balance - #{amount} ${ew.customSqlSegment}")
void updateBalanceByWrapper(@Param("amount") int amount, @Param("ew") LambdaQueryWrapper<User> wrapper);

where id in(1,2,4) 使用自定义sql完成,将wrapper作为参数传入自定义的方法中

通过${ew.customSqlSegment} 转化成 where id in (1,2,4) !!!!!!

 @Test
    public void testCustomSql() {
        int amount = 200;
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getId, 1, 2, 4);
        userMapper.updateBalanceByWrapper(amount, wrapper);
    }

4.2.2 多表联查

理论上来将MyBatisPlus是不支持多表查询的,不过我们可以利用Wrapper中自定义条件结合自定义SQL来实现多表查询的效果。

例如,我们要查询出所有收货地址在北京的并且用户id在1、2、4之中的用户 

普通实现
@Test
public interface UserMapper extends BaseMapper<User> {
    List<User> queryUserByIdAndAddr(List<Long> ids, String city);
}


<select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">
      SELECT *
      FROM user u
      INNER JOIN address a ON u.id = a.user_id
      WHERE u.id
      <foreach collection="ids" separator="," item="id" open="IN (" close=")">
          #{id}
      </foreach>
      AND a.city = #{city}
  </select>

Wrapper构建查询条件实现

基于自定义SQL结合Wrapper的玩法,我们就可以利用Wrapper来构建查询条件,然后手写SELECT及FROM部分,实现多表查询。 查询条件这样来构建:

@Test
void testCustomJoinWrapper() {
    // 1.准备自定义查询条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .in("u.id", List.of(1L, 2L, 4L))
            .eq("a.city", "北京");

    // 2.调用mapper的自定义方法
    List<User> users = userMapper.queryUserByWrapper(wrapper);

    users.forEach(System.out::println);
}

1、在UserMapper中自定义方法:


@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")
List<User> queryUserByWrapper(@Param("ew")QueryWrapper<User> wrapper);

2、也可以在UserMapper.xml中写SQL:

<select id="queryUserByIdAndAddr" resultType="com.itheima.mp.domain.po.User">
    SELECT * FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}
</select>

总结:where条件可以使用wrapper构建,然后作为参数传递

apply()方法构建查询条件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值