Always keep |

奕帆卷卷

园龄:1年4个月粉丝:3关注:0

Mybatis Plus

Mybatis Plus

简介

Mybatis Plus是基于mybatis的一种增强工具,我们可以使用这个组件来简化项目中的单表操作以及其他更复杂的操作。

其特点是:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动会自动注入基本CUBD,性能基本无损耗
  • 强大的CRUD操作:内置通用Mapper,通用Service,仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器
  • 支持Lambda形式调用:通过Lambda表达式,方便的编写各类查询条件,无需再担心字段写错

准备工作

如果想要使用mybatis plus 则需要以下几步:

  • 引入MybatisPlus依赖
  • 定义Mapper

引入依赖

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

定义Mapper

为了简化单表CRUD,MybatisPlus提供了一个基础的BaseMapper接口,在这个接口中已经实现了单表CRUD,所以我们只需要让指定的Mapper接口,让其继承BaseMapper即可。

并且我们在继承BaseMapper的时候指定了一个泛型,这个泛型就是数据库对应的PO,MybatisPlus就是根据PO实体的信息来推断出表的信息,从而生成SQL。

在默认情况下,MybatisPlus会把PO实体的类名驼峰转下划线为表名,所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型,MybatisPlus会将名为id的字段作为主键。

常见注解

@TableName

这个注解用来表名注释,标识实体类对应的表

使用在实体类类名上面

实例

@TableName("user")
public class User {
private Long id;
private String name;
}

TableName注解除了指定表名以外,还可以指定很多其他属性

属性 类型 必须指定 默认值 描述
value String "" 表名
schema String "" schema
keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMap String "" xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludeProperty String[] {} 需要排除的属性名 @since 3.3.1

@TableId

主键注解,用于标记实体类的主键字段

在实体类中的属性上

实例

@TableName("user")
public class User {
@TableId
private Long id;
private String name;
}

@TableId注解有两个属性

属性 类型 必须指定 默认值 描述
value String "" 表名
type Enum IdType.NONE 指定主键类型

type执行的类型有

描述
AUTO 数据库 ID 自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert 前自行 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 方法)

比较常见的有三种:

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

INPUT:手动生成id

ASSIGN_ID:雪花算法生成Long类型的全局唯一id

@TableFieId

普通字段注解,标记属性是否是表中的字段及哪个字段,一般特殊字段才需要这样的标记

使用在实体类属性之上

@TableName("user")
public class User {
@TableId
private Long id;
private String name;
private Integer age;
@TableField("isMarried")
private Boolean isMarried;
@TableField("concat")
private String concat;
}

@TableFieId一般情况下不需要添加,一些特殊情况下除外:

  • 成员变量名于数据库字段名不一致
  • 成员变量是以isxxx命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符
  • 成员变量名与数据库一致,但是与数据库的关键字冲突,使用@TableFieId注解给字段名添加转义

常见配置

MybatisPlus也支持基于yaml文件的自定义配置

大多数的配置都有默认值,因此我们都无需配置,但还是有一些没有默认值的

  • 实体类的别名扫描包
  • 全局id类型
mybatis-plus:
type-aliases-package: com.mp.domain.po
global-config:
db-config:
id-type: auto # 全局id类型为自增长

需要注意的是,MyBatisPlus也是支持手写SQL的,而mapper文件的读取地址可以自己配置:

mybatis-plus:
mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。

也就是说,只有我们把mapper.xml文件放到上面路径目录下就一定会被加载。

进阶

条件构造器

除了增删改查的SQL语句都需要指定where条件,因此BaseMapper中提供的相关方法除了以id作为where条件以外,还支持更加复杂的where条件

在继承的BaseMapper中,复杂where条件的查询方法中的参数wrapper就是条件构造的抽象类。

wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法,而QueryWrapper在AbstactWrapper的基础上拓展了一个select方法,允许指定查询字段。而UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法,允许指定SQL的SET部分。

QueryWrapper

无论是修改还是删除查询,都可以使用QueryWrapper来构建查询条件。

查询:

查询出名字中带o的,存款大于等于1000元的人(id,username,info,balance).

package com.itheima.mp.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;
/**
* 查询出名字中带o的,存款大于等于1000元的人(id,username,info,balance)
*/
@Test
public void testQueryWrapper1() {
//1、构造查询条件;构造 where username like 'o' and balance >= 1000
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.
select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
//2、查询
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
}

更新:

更新用户名为jack的用户的余额为20000

/**
* 更新用户名为jack的用户的余额为2000
*/
@Test
public void testUpdate() {
//1、构造查询条件;构造 where username = 'jack'
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "jack");
// user中非null的字段,会进行set操作
User user = new User();
user.setBalance(2000);
//2、修改;只更新非空字段
userMapper.update(user, queryWrapper);
}

UpdateWrapper

基于BaseMapper中的update方法更新时只能直接赋值,而如果想要完成一些复杂的需求,则需要进行利用UpdateWrapper中的setSQL功能

/**
* 更新id为1,2,4的用户的余额,扣200
*/
@Test
public void testUpdateWrapper(){
//1、构造更新条件对象
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
// set balance = balance - 200
updateWrapper.setSql("balance = balance - 200");
// where id in (1,2,4)
updateWrapper.in("id", 1, 2, 4);
//2、更新
userMapper.update(null, updateWrapper);
}

LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,这在编程规范中是不推荐的

其中一种办法是基于变量的getter方法结合反射技术,因此我们只要将条件对应的字段的getter方法传递给MybatisPlous,它就能计算出对应的变量名。

mybatisplus又提供了一套基于Lambda的Wrapper

  • LambdaQueryWrapper
  • LambdaUpdateWrapper

分别对应QueryWrapper和UpdateWrapper

同样的查询需求:查询出名字中带o的,存款大于等于1000元的人

/**
* 查询出名字中带o的,存款大于等于1000元的人(id,username,info,balance)
*/
@Test
public void testLambdaQueryWrapper() {
//1、构造查询条件;构造 where username like 'o' and balance >= 1000
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.
select(User::getId, User::getUsername, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
//2、查询
List<User> list = userMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}

自定义拼接SQL

Mybatisplus提供了自定义SQL功能,可以让我们利用Wrapper生成查询条件,再结合Mapper.xml拼接SQL

/**
* 更新id为1,2,4的用户的余额,扣200
*/
@Test
public void testCustomWrapper(){
//1、构造更新条件对象
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", 1, 2, 4);
//2、更新; 调用自定义的更新方法,传入更新数值与查询条件对象
userMapper.updateBalanceByWrapper(200, queryWrapper);
}

在Mapper中添加如下方法

@Update("UPDATE user SET balance = balance - #{amount} ${ew.customSqlSegment}")
void updateBalanceByWrapper(@Param("amount") int amount, @Param("ew") QueryWrapper<User> queryWrapper);

注意:

在上述的执行语句中ew及其customSqlSegent都不能修改

  1. queryWrapper查询条件对象相当于对要执行的语句进行了语句的拼接
  2. ${ew.customSqlSegment} 可以使用在注解中,也可以使用在 Mapper.xml文件中进行SQL语句的拼接

Service接口

MybatisPlus不仅提供了BaseMapper,还提供了通用的Service接口及其默认实现,封装了一些常用的service模板方法,通用接口为IService,默认实现为ServiceImpl,其中封装的方法可以分为:

  • save:新增
  • remove:删除
  • update:更新
  • get:查询单个结果
  • list:查询集合结果
  • count:计数
  • page:分页查询

基本方法说明

新增

  • save是新增单个元素
  • saveBatch是批量新增
  • saveOrUpdate是根据id判断,如果数据存在就更新,不存在则新增
  • saveOrUpdateBatch是批量的新增或修改

删除

  • removeById:根据id删除

  • removeByIds:根据id批量删除

  • removeByMap:根据Map中的键值对为条件删除

  • remove(Wrapper):根据Wrapper条件删除

修改

  • updateById:根据id修改
  • update(Wrapper):根据UpdateWrapper修改,Wrapper中包含setwhere部分
  • update(T,Wrapper):按照T内的数据修改与Wrapper匹配到的数据
  • updateBatchById:根据id批量修改

Get

  • getById:根据id查询1条数据
  • getOne(Wrapper):根据Wrapper查询1条数据
  • getBaseMapper:获取Service内的BaseMapper实现,某些时候需要直接调用Mapper内的自定义SQL时可以用这个方法获取到Mapper

List

  • listByIds:根据id批量查询
  • list(Wrapper):根据Wrapper条件查询多条数据
  • list():查询所有

Count

  • count():统计所有数量
  • count(Wrapper):统计符合Wrapper条件的数据数量

getBaseMapper

当我们在service中要调用Mapper中自定义SQL时,就必须获取service对应的Mapper,就可以通过这个方法;

基本用法

由于Service中经常需要定义与业务有关的自定义方法,因此我们不能直接使用IService,而是自定义Service接口,然后继承IService以拓展方法。同时,让自定义的Service实现类继承ServiceImpl,这样就不用自己实现IService中的接口了

改进Controller方法

在Service中对LambdaQueryWrapper和LambdaUpdateWrapper的用法进一步做了简化,我们无需自己通过new的方式来创建wrapper,而是直接调用lambdaQuery和lambdaUpdate方法

/**
* 根据查询条件userQuery 查询用户列表
* @param userQuery 查询条件
* @return 用户列表
*/
@ApiOperation("根据查询条件userQuery 查询用户列表")
@PostMapping("/list")
public List<UserVO> queryList(@RequestBody UserQuery userQuery) {
String userName = userQuery.getName();
Integer status = userQuery.getStatus();
Integer minBalance = userQuery.getMinBalance();
Integer maxBalance = userQuery.getMaxBalance();
/*LambdaQueryWrapper<User> queryWrapper = new QueryWrapper<User>().lambda()
.like(StrUtil.isNotBlank(userName), User::getUsername, userName)
.eq(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance);
List<User> userList = userService.list(queryWrapper);*/
//改造为service中的lambdaQuery()
List<User> userList = userService.lambdaQuery()
.like(StrUtil.isNotBlank(userName), User::getUsername, userName)
.eq(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance)
.list();
return BeanUtil.copyToList(userList, UserVO.class);
}

lambdaQuery方法中除了可以构建条件,还需要在链式编程的最后添加一个list(),这是在告诉MP我们的调用结果需要一个list集合,另外可选的方法还有

  • .one():最多1个结果
  • .list():返回集合结果
  • .count():返回计数结果

MybatisPlus会根据链式编程的最后一个方法来判断最终的返回结果

本文作者:开卷日记

本文链接:https://www.cnblogs.com/yifan0820/p/18035193

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   奕帆卷卷  阅读(100)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起