Bootstrap

最新版MyBatis-Plus使用详解

作者简介:☕️大家好,我是intelligent_M,一个Java后端开发者!
当前专栏:intelligent_M——MyBatisPlus ,CSDN博客。

后续会更新Java相关技术栈以及链表哈希表二叉树…,回溯算法贪心算法…等等算法题。
创作不易 欢迎点赞评论!!!


MyBatisPlus是什么?有什么功能?

  • MyBatisPlus是一个基于MyBatis的增强工具(只做增强不做修改无侵入性),能够提高开发效率和代码质量。它提供了很多MyBatis不具备的功能,包括:
  1. 生成器:通过简单的配置可以自动生成JavaBean、Mapper和XML文件。

  2. 分页插件:支持多种数据库的分页查询,包括MySQL、Oracle、SQLServer等。

  3. 条件构造器:提供一种类似于SQL语句的方式来构造查询条件,避免了手写SQL的繁琐。

  4. SQL注入器:通过自定义SQL注入器,可以在不使用XML文件的情况下编写复杂SQL语句。

  5. 数据库操作工具类:提供了一些常用的数据库操作方法,例如批量插入、更新、删除等。

  6. 其他:还提供了缓存、性能分析等功能,以及对Spring Boot的支持。

  • 总之,MyBatisPlus提供了很多便利的功能,可以大大减少开发人员的工作量,提高开发效率和代码质量。

一、快速入门

1.入门案例

  • 需求:基于项目,实现下列功能:
    • 新增用户功能
    • 根据id查询用户
    • 根据id批量查询用户
    • 根据id更新用户
    • 根据id删除用户
  • 1.引入依赖
    MybatisPlus提供了starter,实现了自动Mybatis以及MybatisPlus的自动装配功能,坐标如下:
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>
  • 2.定义Mapper
    自定义的Mapper继承MybatisPlus提供的BaseMapper接口:

在这里插入图片描述

  • 3.调用继承的BaseMapper接口的方法
@SpringBootTest
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testInsert() {
        User user = new User();
        user.setId(5L);
        user.setUsername("Lucy");
        user.setPassword("123");
        user.setPhone("18688990011");
        user.setBalance(200);
        user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        //userMapper.saveUser(user);//注释掉的都是用Mybatis xml文件实现的方法
        userMapper.insert(user);
    }

    @Test
    void testSelectById() {
        //User user = userMapper.queryUserById(5L);
        User user = userMapper.selectById(5L);
        System.out.println("user = " + user);
    }


    @Test
    void testQueryByIds() {
        //List<User> users = userMapper.queryUserByIds(List.of(1L, 2L, 3L, 4L));
        List<User> users = userMapper.selectBatchIds(List.of(1l, 2l, 3l, 4l));
        users.forEach(System.out::println);
    }

    @Test
    void testUpdateById() {
        User user = new User();
        user.setId(5L);
        user.setBalance(20000);
        //userMapper.updateUser(user);
        userMapper.updateById(user);
    }

    @Test
    void testDeleteUser() {
        //userMapper.deleteUser(5L);
        userMapper.deleteById(5L);
    }
}

2.常见注解

  • MybatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表的信息
    • 通常有以下约定
    • 类名驼峰转下划线作为表名
    • 名为id的字段作为主键
    • 变量名驼峰转下划线作为表的字段名

在这里插入图片描述

在这里插入图片描述

  • MybatisPlus中比较常用的几个注解如下:

  • @Tablename:用来指定表名(与数据库表名不一致时可指定)

  • @TableId:用来指定表中的主键字段信息

    • IdType枚举:
      • AUTO:数据库自增
      • INPUT:通过set方法自行输入
      • ASSIGN_ID:分配ID,接口IdentifierGenerator的方法nextId来生成 id,默认实现类为DefaultidentifierGenerator雪花算法
  • @TableFiled:用来指定表中的普通字段信息

    • @TableField常见使用场景
      • 成员变量名与数据库字段名不一致
      • 成员变量名以is开头,且是布尔值
      • 成员变量名与数据库关键字冲突
      • 成员变量不是数据库字

在这里插入图片描述

3.常见配置

  • MybatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置。例如:
    在这里插入图片描述

4.MyBatisPlus使用的基本流程是什么?

  • 1.引入起步依赖
  • 2.自定义Mapper继承BaseMapper
  • 3.在实体类上添加注解声名表信息
  • 4.在application.yml中根据需要添加配置

5.乐观锁与悲观锁

  • 乐观锁是一种轻量级锁,通过在数据表中添加一个版本号字段或时间戳字段,每次更新数据时将版本号或时间戳加一,并在更新语句中带上当前版本号或时间戳的条件,当版本号或时间戳不一致时更新失败。乐观锁不会对数据库进行锁定,而是在应用层上检查并防止并发的数据修改,适用于多读少写的情况。

  • MyBatis-Plus 的乐观锁实现方式是:在实体类中添加一个 @Version 注解标注版本号字段,更新数据时 MyBatis-Plus 会自动在更新语句中带上当前版本号的条件。

  • 悲观锁是一种重量级锁,在对数据库执行操作前对数据库表或数据行进行锁定,防止其他事务进行修改,直到当前事务提交或回滚后才释放锁。悲观锁适用于多写少读的情况。

  • MyBatis-Plus 的悲观锁实现方式是:使用 selectForUpdate 或 selectForUpdateNowait 方法进行锁定查询,将数据行锁定,直到事务提交或回滚后才释放锁。需要注意的是使用悲观锁会对数据库进行锁定,可能会影响系统吞吐量和性能。

二、核心功能

1.条件构造器

  • MybatisPlus支持各种复杂的where条件,可以瞒足日常开发需求
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 案例需求(基于QueryWrapper的查询)
  • 1.查询出名字中带o的,存款大于等于1000元的人的id,username,info,balance字段
    在这里插入图片描述
@Test//1.查询出名字中带o的,存款大于等于1000元的人的id,username,info,balance字段
    void testQueryWrapper(){
        //1.构造条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        //2.查询
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);//遍历输出
    }
  • 2.更新用户名为jack的用户的余额
    在这里插入图片描述
@Test//2.更新用户名为jack的用户的余额
    void testUpdateByQueryWrapper(){
        //1.要更新的数据
        User user = new User();
        user.setBalance(2000);
        //2.更新的条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");
        //3.执行更新
        userMapper.update(user, wrapper);
    }
  • 案例(基于UpdateWrapper的更新)
  • 更新id为1,2,4的用户的跃,扣200
@Test//更新id为1,2,4的用户的余额,扣200
    void testUpdateWrapper(){
        List<Long> ids = List.of(1L, 2L, 4L);
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                .in("id", ids);

        userMapper.update(null, wrapper);
    }
  • 关于Lambda的条件构造器(利用反射获取实体类的字段,避免了硬编码)
 @Test//1.查询出名字中带o的,存款大于等于1000元的人的id,username,info,balance字段
    void testQueryWrapper(){
        //1.构造条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        //2.查询
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);//遍历输出
    }
  • 条件构造器的用法
    • QueryWrapper和LambdaQueryWrapper通常用来构建select,delete, update,和where条件部分
    • UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用
    • 尽量使用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码

2.自定义SQL

  • 我们可以利用MyBatisPlus的Wrapper来构建复杂的where条件,然后自己定义SQL语句中的剩下的部分
  • 1.基于Wrapper构建where条件
  //自定义Sql
    void testCustomSqlUpdate(){
        //1.更新条件
        List<Long> ids = List.of(1L, 2L, 4L);
        int amount = 200;
        //2.定义条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);
        //3.调用自定义sql方法
        userMapper.updateBalanceByIds(wrapper , amount);
    }
  • 2.在mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper, @Param("amount") int amount);
  • 3.自定义SQL,并使用Wrapper条件(写在mapper.xml文件中或者用注解写sql)
<update id="updateBalanceByIds">
        UPDATE user SET balance = balance - #{amount} ${ew.customSqlSegment}
    </update>

3.IService接口基本用法

在这里插入图片描述
在这里插入图片描述

  • UserServiceImpl类间接实现了IService接口有了接口里的方法,UserServiceImpl类继承了ServiceImpl有了IService里面的方法的实现
  • Mp的Service接口使用流程是怎样的?
    • 自定义Service接口继承IService接口
      在这里插入图片描述
    • 自定义Service实现类,实现自定义接口并继承ServiceImpl类
      在这里插入图片描述

4.IService开发基础业务接口

  • 案例:基于Restful风格实现下列接口
    在这里插入图片描述
/**
 * @author MBY
 * @version 1.0
 */
@Api(tags = "用户管理接口")//swagger注解
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor//必备的构造函数,它只会对那么需要在一开始就初始化的变量去做构造
public class UserController {

    private final IUserService userService;//加了final将来是构造函数的一部分会被spring自动注入

    @ApiOperation("新增用户接口")
    @PostMapping
    public void saveUser(@RequestBody UserFormDTO userDTO){
        //1.把DTO拷贝到PO
        User user = BeanUtil.copyProperties(userDTO, User.class);
        //新增
        userService.save(user);
    }

    @ApiOperation("删除用户接口")
    @DeleteMapping("{id}")
    public void deleteUserById(@ApiParam("用户id") @PathVariable("id") Long id){
        userService.removeById(id);
    }

    @ApiOperation("根据id查询用户接口")
    @GetMapping("{id}")
    public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Long id){
        //1.查询用户PO
        User user = userService.getById(id);
        //2.把PO拷贝到VO
        return BeanUtil.copyProperties(user, UserVO.class);
    }

    @ApiOperation("根据id批量查询用户接口")
    @GetMapping
    public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
        //1.查询用户PO
        List<User> users = userService.listByIds(ids);
        //2.把PO拷贝到VO
        return BeanUtil.copyToList(users, UserVO.class);
    }
}

5.IService开发复杂业务接口

  • 延续上面的第五个接口 根据id扣减余额
  • controller层
@ApiOperation("扣减用户余额接口")
    @PutMapping("/{id}/deduction/{money}")
    public void deductBalance(
            @ApiParam("用户id") @PathVariable("id") Long id,
            @ApiParam("扣减的金额") @PathVariable("money" )Integer money){
        userService.deductBalance(id, money);
    }
  • IUserService
void deductBalance(Long id, Integer money);
  • UserServiceImpl
@Override
    public void deductBalance(Long id, Integer money) {
        //1.查询用户
        User user = getById(id);
        //2.校验用户状态
        if(user == null || user.getStatus() == 2){
            throw new RuntimeException("用户状态异常!");
        }
        //3.校验余额是否充足
        if(user.getBalance() < money){
            throw new RuntimeException("用户余额不做!");
        }
        //4.扣减余额update user set balance = balance - ?
        baseMapper.deductBalance(id, money);
    }
  • UserMapper
@Update("update user set balance = balance - #{money} where id = #{id}")
    void deductBalance(Long id, Integer money);
  • 总结
    • 对于简单的增删改查业务,我们都可以在controller层调用mp中的service方法,无需写自定义的service或者mapper。
    • 当业务相对复杂,mp中的方法无法满足我们的需求时,就需要我们自定义service方法并且在其中编写业务逻辑。
    • 当baseMapper中的方法不足以满足业务需求就需要我们自定义方法自定义SQL语句(用注解或者mapper.xml配置文件)。

6.IService的Lambda方法

  • 案例一(LambdaQuery)
  • 需求:实现一个根据复杂条件查询用户的接口,查询条件如下:
    • name:用户名关键字,可以为空
    • status:用户状态,可以为空
    • minBalance:最小余额,可以为空
    • maxBalance:最大余额,可以为空
  • controller
 @ApiOperation("根据复杂条件查询用户接口")
    @GetMapping("/list")
    public List<UserVO> queryUser(UserQuery query){
        //1.查询用户PO
        List<User> users = userService.queryUsers(
                query.getName(), query.getStatus(), query.getMinBalance(), query.getMaxBalance());
        //2.把PO拷贝到VO
        return BeanUtil.copyToList(users, UserVO.class);
    }
  • UserServiceImpl
 @Override
    public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
        return lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .ge(minBalance != null , User::getBalance, minBalance)
                .le(maxBalance != null, User::getBalance, maxBalance)
                .list();
    }
  • 案例二IService的Lambda更新(LambdaUpdate)
  • 需求:改造根据id修改用户余额的接口,要求如下:
    • 完成对用户状态校验
    • 完成对用户余额校验
    • 如果扣减后余额为0,则将用户status修改为冻结状态(2)
 @Override
    @Transactional
    public void deductBalance(Long id, Integer money) {
        //1.查询用户
        User user = getById(id);
        //2.校验用户状态
        if(user == null || user.getStatus() == 2){
            throw new RuntimeException("用户状态异常!");
        }
        //3.校验余额是否充足
        if(user.getBalance() < money){
            throw new RuntimeException("用户余额不做!");
        }
        //4.扣减余额update user set balance = balance - ?
        //baseMapper.deductBalance(id, money);
        int remainBalance = user.getBalance() - money;
        lambdaUpdate()
                .set(User::getBalance, remainBalance)
                .set(remainBalance == 0, User::getStatus, 2)
                .eq(User::getId, id)
                .eq(User::getBalance, user.getBalance())// 乐观锁
                .update();
    }
  • 总结
    • LambdaQuery主要用于帮助我们构建复杂查询
    • LambdaUpdate主要用于帮助我们构建复杂更新
    • update方法最后要加上.update()否则不会执行
    • 两者都可加上条件(condation)满足才会拼接SQL,实现动态SQL

7.IService的批量新增

  • 需求:批量插入10万条用户数据,并作出对比:
    • 普通for循环插入
    • IService的批量插入
    • 开启rewriteBatchedStatements=true参数
  • 批处理方案:
    • 普通for循环逐条插入速度极差,不推荐
    • MP的批量新增,基于预编译的批处理,性能不错
    • 配置jdbc参数,开启rewriteBatchedStatements,性能最好

三、扩展功能

1.代码生成器

  • 代码生成

  • 对于同一个实体来说以下代码比较固定,重复写又比较繁琐
    在这里插入图片描述

  • 代码生成器就诞生了

  • 这里有MybatisPlus提供的代码生成器的官方文档- 代码生成器(点击OPEN)这里不做介绍

  • 这里提供一款非官方的Mybatisplus代码生成的一个插件
    在这里插入图片描述

  • 使用步骤如下:

  • 点击other
    在这里插入图片描述

  • 点击Cinfig Database
    在这里插入图片描述

  • 点击test connect看能否连接成功
    在这里插入图片描述

  • 点击Code Generator
    在这里插入图片描述

  • 选择表做相关配置然后点击save点击 code generator即可生成相应的代码
    在这里插入图片描述

2.DB静态工具

  • 这个工具是最新版的MybatisPlus才有的功能
  • 静态工具(里面的方法都是静态的无法利用反射获取对象)
  • 使用静态工具可以解决循环依赖相互注入的问题

在这里插入图片描述

  • 这里不做重点讲解

3.逻辑删除

  • 逻辑删除就是基于代码逻辑模拟删除效果,但并不会正真删除数据。思路如下:
  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为1
  • 当查询时只查询标记为0的数据
  • 例如逻辑删除字段为deleted:
  • 删除操作
    在这里插入图片描述
  • 查询操作
    在这里插入图片描述
  • 这时我做的测试,删除方法变成update语句,查询方法后面多了对逻辑删除字段deleted的判断
    在这里插入图片描述
  • MybatisPlus提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可:
    在这里插入图片描述
    逻辑删除本身也有自己的问题,比如:
  • 会导致数据库表垃圾数据越来越多,影响查询效率
  • SQL中全都需要对逻辑字段做判断,影响查询效率
    因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其他表的办法来解决

4.枚举处理器

  • User类中有一个用户状态字段:
  • 使用第一步:创建新的类定义相应的枚举利用注解进行标记开发
    在这里插入图片描述
  • 使用第二步:在applicatin.yaml中配置全局枚举处理器
    在这里插入图片描述
  • 不过这里枚举返回给前端的数据时枚举,我们可以通过@JsonValue注解来决定返回哪个数据
    在这里插入图片描述

5.JSON处理器

  • 数据库表中user表中有一个json类型的字段:
    在这里插入图片描述
  • 处理前 (该字段在Java中用的String类型)
    在这里插入图片描述
  • 处理后
    在这里插入图片描述

四、插件功能

  • MybatisPlus提供的内置拦截器有下面这些
    在这里插入图片描述
  • 不过我们常用的也就时分页插件

1.分页插件基本用法

  • 首先,要在配置类中注册MybatisPlus的核心插件,同时添加分页插件:
    在这里插入图片描述
  • 接着就可以使用分页的API了
    在这里插入图片描述
  • 测试使用分页插件
  @Test
    void testPageQuery() {
        int pageNo = 1, pageSize = 2;
        //1.准备分页条件
        //1.1分页条件
        Page<User> page = Page.of(pageNo, pageSize);
        //1.2排序条件
        page.addOrder(new OrderItem("balance", true));
        page.addOrder(new OrderItem("id", true));
        //2.分页查询
        Page<User> p = userService.page(page);
        //3.解析
        long total = p.getTotal();
        System.out.println("total = " + total);
        long pages = p.getPages();
        System.out.println("pages = " + pages);
        List<User> users = p.getRecords();
        users.forEach(System.out::println);

    }

2.通用分页实体

  • 封装统一的查询条件(要么直接使用要么继承)
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
    @ApiModelProperty("页码")
    private Integer pageNo;
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    @ApiModelProperty("排序字段")
    private String sortBy;
    @ApiModelProperty("是否升序")
    private Boolean isAsc;
}
  • 封装统一的返回值
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页结果")
public class PageDTO<V> {
    @ApiModelProperty("总条数")
    private Long total;
    @ApiModelProperty("总页数")
    private Long pages;
    @ApiModelProperty("集合")
    private List<V> list;
}

3.通用分页实体与MP转换

  • 下面这里看不懂的可以不看,就是封装了一些业务简化开发
  • 在PageQuery中定义方法,将PageQuery的对象转为MyBatisPlus中的Page对象
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
    @ApiModelProperty("页码")
    private Integer pageNo;
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    @ApiModelProperty("排序字段")
    private String sortBy;
    @ApiModelProperty("是否升序")
    private Boolean isAsc;

    //自动的将PageQuery对象转为MyBatisPlus中的Page对象
    public <T>  Page<T> toMpPage(OrderItem ... orders){
        // 1.分页条件
        Page<T> p = Page.of(pageNo, pageSize);
        // 2.排序条件
        // 2.1.先看前端有没有传排序字段
        if (sortBy != null) {
            p.addOrder(new OrderItem(sortBy, isAsc));
            return p;
        }
        // 2.2.再看有没有手动指定排序字段
        if(orders != null){
            p.addOrder(orders);
        }
        return p;
    }

    public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc){
        return this.toMpPage(new OrderItem(defaultSortBy, isAsc));
    }

    public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {
        return toMpPage("create_time", false);
    }

    public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {
        return toMpPage("update_time", false);
    }
}

  • 在PageDTO中定义方法,将MyBatisPlus中的Page结果转为PageDTO结果
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页结果")
public class PageDTO<V> {
    @ApiModelProperty("总条数")
    private Long total;
    @ApiModelProperty("总页数")
    private Long pages;
    @ApiModelProperty("集合")
    private List<V> list;

    /**
     * 返回空分页结果
     * @param p MybatisPlus的分页结果
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> empty(Page<P> p){
        return new PageDTO<>(p.getTotal(), p.getPages(), Collections.emptyList());
    }

    /**
     * 将MybatisPlus分页结果转为 VO分页结果
     * @param p MybatisPlus的分页结果
     * @param voClass 目标VO类型的字节码
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> of(Page<P> p, Class<V> voClass) {
        // 1.非空校验
        List<P> records = p.getRecords();
        if (records == null || records.size() <= 0) {
            // 无数据,返回空结果
            return empty(p);
        }
        // 2.数据转换
        List<V> vos = BeanUtil.copyToList(records, voClass);
        // 3.封装返回
        return new PageDTO<>(p.getTotal(), p.getPages(), vos);
    }

    /**
     * 将MybatisPlus分页结果转为 VO分页结果,允许用户自定义PO到VO的转换方式
     * @param p MybatisPlus的分页结果
     * @param convertor PO到VO的转换函数
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> of(Page<P> p, Function<P, V> convertor) {
        // 1.非空校验
        List<P> records = p.getRecords();
        if (records == null || records.size() <= 0) {
            // 无数据,返回空结果
            return empty(p);
        }
        // 2.数据转换
        List<V> vos = records.stream().map(convertor).collect(Collectors.toList());
        // 3.封装返回
        return new PageDTO<>(p.getTotal(), p.getPages(), vos);
    }
}

五、总结

  • MyBatis-Plus是MyBatis的增强工具,主要用于简化和增强MyBatis的操作。为了掌握MyBatis-Plus,我们需要掌握以下重点:

1.MyBatis-Plus的基本使用:了解MyBatis-Plus的配置和使用方法,包括实体类、映射文件、Dao接口以及MyBatis-Plus提供的常用方法和工具类。

2.MyBatis-Plus的高级查询:掌握MyBatis-Plus提供的高级查询功能,包括条件构造器、Wrapper、QueryWrapper、LambdaWrapper等,并且了解如何使用这些功能进行复杂查询。

3.分页查询:掌握MyBatis-Plus的分页查询功能,了解分页查询的原理和实现方法,并且了解MyBatis-Plus的分页查询API和使用方法。

4.代码自动生成:掌握MyBatis-Plus提供的代码自动生成功能,了解如何使用MyBatis-Plus自动生成实体类、Mapper接口和XML映射文件。

5.性能优化:了解MyBatis-Plus的性能优化技巧,包括缓存、批量操作、SQL优化等,以便在实际应用中提高系统的性能。

  • 综上所述,掌握MyBatis-Plus需要我们掌握其基本使用、高级查询、分页查询、代码自动生成和性能优化等重点。

有需要详细了解MyBatisPlus的小伙伴,可以前往MyBatisPlus的官方文档(点击OPEN)

;