Mybatis-Plus 全面解析讲解---全干货篇

127 阅读15分钟

Mybatis-Plus 全面解析讲解---全干货篇

1. 前言

1.1 MP是什么

MyBatis-Plus(简称MP)是 MyBatis 的增强工具库,它是在 MyBatis 的基础上进行了扩展和增强,旨在简化开发,提高效率。MyBatis-Plus 提供了一些常用且便捷的功能,使开发人员能够更轻松地进行数据库操作。 主要特点和功能包括:

  • CRUD操作的便捷方法: MyBatis-Plus 提供了通用的 Mapper 接口,通过继承该接口,即可使用其中提供的诸多便捷的 CRUD 操作方法,无需手动编写 SQL。
  • 条件构造器: MyBatis-Plus 提供了强大的条件构造器,可以通过代码构建复杂的查询条件,避免手动拼接 SQL。
  • 分页插件: 提供了分页查询的支持,简化了分页操作的代码编写。
  • 代码生成器: MyBatis-Plus 提供了代码生成器,可以根据数据库表自动生成对应的实体类、Mapper 接口以及 XML 文件,加速开发过程。
  • 性能分析插件: 可以方便地进行 SQL 执行性能分析,帮助开发人员优化数据库访问性能。
  • 乐观锁插件: 支持乐观锁的功能,确保数据的一致性和并发安全性。

1.2 为什么要用MP

引用MP的原话就是如下:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

2. 快速开始

2.1 配置依赖

     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 ​
         <dependency>
             <groupId>com.mysql</groupId>
             <artifactId>mysql-connector-j</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-boot-starter</artifactId>
             <version>3.5.3</version>
         </dependency>
     </dependencies>

2.2 配置yml

 server:
   port: 10086 
   servlet:
     context-path : /api  #访问前缀
 spring:
   datasource:
     url: jdbc:mysql://localhost:3306/db111?useUnicode=true&characterEncoding=gbk&serverTimezone=UTC
     driver-class-name: com.mysql.cj.jdbc.Driver
     username: root
     password: 111
 # 上面是配置数据库,注意换成自己的
 mybatis-plus:
   configuration:
     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #MP日志配置
   global-config:
     db-config:
       id-type: assign_id     #配置默认ID类型 在实体类也可以具体配置,之后在注解开发会细讲
       logic-delete-field: deleted   # 默认软删除字段,在实体类也可以具体配置,
       logic-delete-value: 1    # 默认代表删除的值,在实体类也可以具体配置,
       logic-not-delete-value: 0   # 默认代表没被删除的值,在实体类也可以具体配置,
     enable-sql-runner: true     # 开启sqlRunner(用于发起原生sql的方式,之后在原生sql会细讲)

2.3 配置实体类

 package com.example.mptest.pojo.entity;
 ​
 import com.baomidou.mybatisplus.annotation.*;
 import lombok.*;
 ​
 /**
  * @author hfLiuX
  * @version 1.0
  * @description: 酒店信息实体类
  * @date 2023/12/5 15:11
  */
 @AllArgsConstructor
 @NoArgsConstructor
 @Setter
 @Getter
 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  //配置主键ID类型,之后在注解开发会细讲
     private Long id;
     private String name;
     private String address;
     private double price;
     private int score;
     private String brand;
     private String city;
     private String starName;
     private String business;
     private String latitude;
     private String longitude;
     private String pic;
 ​
     @TableLogic(value = "0",delval = "1")//这个也可以在yml文件进行全局配置
     private int deleted;//软删除字段,0代表未删除,1代表已删除
 ​
     @TableField(exist = false)//代表数据库中没有这个字段
     private boolean status;
 ​
 ​
 }

2.4 配置Mapper

 package com.example.mptest.mapper;
 ​
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.example.mptest.pojo.entity.Hotel;
 ​
 import java.util.Collection;
 import java.util.List;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:20
  */
 public interface HotelMapper extends BaseMapper<Hotel> {
 //是的,没有看错 其他什么都不用写了,也不需要再配置XML的sql代码了(特别复杂的sql还是要单独写的)
 }
 ​

2.5 简单的CRUD

 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:48
  */
 @SpringBootTest
 public class TestAdd {
 ​
     @Autowired
     private HotelMapper hotelMapper;
 ​
     @Test
     public void testAddSigal() {
         System.out.println(("----- 插入单条数据数据 ------"));
         Hotel hotel1=new Hotel(null,"天津唐拉雅秀国际酒店","和平路199号",999,47,"唐拉雅秀","天津","二钻","小白楼","40.10144","116.380641","https://m.tuniucdn.com/fb2/t1/G2/M00/C7/CB/Cii-T1km_5eICnpJAAHOWN1GylMAAKYJwF0Hp8AAc5w000_w200_h200_c1_t0.jpg",0,false);
         int insert = hotelMapper.insert(hotel1);
         System.out.println(insert);
     }
     
     
        @Autowired
     HotelMapper hotelMapper;
 ​
     @Test
     public void testDeleteCommon() {
         System.out.println(("----- 根据ID删除单条数据------"));
         int i = hotelMapper.deleteById(2048047291L);
         System.out.println(i);
     }
     
     
         @Test
     public void testSelect() {
         System.out.println(("----- 查询所有数据 ------"));
         List<Hotel> hotels = hotelMapper.selectList(null);//里面是查询条件
         for (int i=0;i<hotels.size();i++){
             System.out.println(hotels.get(i).toString());
         }
     }
     
     
         @Test
     public void testUpdate() {
         System.out.println(("----- 根据ID修改单条数据 ------"));
         Hotel hotel1=new Hotel();
         hotel1.setId(2056105938L);
         hotel1.setAddress("丽泽金融商务区凤凰路新址");
         int i = hotelMapper.updateById(hotel1);
         System.out.println(i);
     }
 ​
     
 }
 ​

这些都可以正常运行后,那么就证明MP启动成功,基础的配置也都搭建完成,可以继续了

3. 注解开发

其实主要都是在实体类中的注解

3.1 TableName

  • 描述:表名注解,标识实体类对应的表
  • 使用位置:实体类
 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  
     private Long id;
     private String name;
     private String address;
 }
属性类型必须指定默认值描述
valueString""表名
schemaString""schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMapString""xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludePropertyString[]{}需要排除的属性名 @since 3.3.1

3.2 TableId

  • 描述:主键注解
  • 使用位置:实体类主键字段
 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  //配置主键ID类型
     private Long id;
     private String name;
     private String address;
     private double price;
     private int score;
     private String brand;
     private String city;
 }
属性类型必须指定默认值描述
valueString""主键字段名
typeEnumIdType.NONE指定主键类型

3.3 IdType

 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  //配置主键ID类型
     private Long id;
     private String name;
     private String address;
     private double price;
     private int score;
     private String brand;
     private String city;
 }
描述
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)

3.4 TableField

  • 描述:字段注解(非主键)
 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  //配置主键ID类型,之后在注解开发会细讲
     private Long id;
     
     
     @TableField("hotel_name")//代表数据库的字段名是hotel_name
     private String name;
     
     @TableField(exist = false)//代表数据库中没有这个字段
     private boolean status;
     private String address;
 ​
 }
属性类型必须指定默认值描述
valueString""数据库字段名
existbooleantrue是否为数据库表字段
conditionString""字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}参考(opens new window)
updateString""字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
insertStrategyEnumFieldStrategy.DEFAULT举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnumFieldStrategy.DEFAULT举例:IGNORED update table_a set column=#{columnProperty}
whereStrategyEnumFieldStrategy.DEFAULT举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
numericScaleString""指定小数点后保留的位数

3.5 Version

 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     
     @Version
     private int version;//乐观锁的字段设置(注意需要去加拦截器)
 ​
 }
  • 描述:乐观锁注解、标记 @Version 在字段上

3.6 TableLogic

  • 描述:表字段逻辑处理注解(逻辑删除
 @TableName("tb_hotel")  //配置数据库名
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)  //配置主键ID类型,之后在注解开发会细讲
     private Long id;
     @TableField("hotel_name")//代表数据库的字段名是hotel_name
     private String name;
 ​
     @TableLogic(value = "0",delval = "1")//这个也可以在yml文件进行全局配置
     private int deleted;//软删除字段,0代表未删除,1代表已删除
 ​
 ​
 }
属性类型必须指定默认值描述
valueString""逻辑未删除值
delvalString""逻辑删除值

3.7 OrderBy

  • 描述:内置 SQL 默认指定排序,优先级低于 wrapper条件查询
属性类型必须指定默认值描述
ascbooleantrue是否倒序查询
sortshortShort.MAX_VALUE数字越小越靠前

4. CRUD详解

4.1 查询操作

 package com.example.mptest;
 ​
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.example.mptest.mapper.HotelMapper;
 import com.example.mptest.pojo.entity.Hotel;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 ​
 import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:29
  */
 @SpringBootTest
 public class TestSelect {
 ​
     @Autowired
     private HotelMapper hotelMapper;
 ​
     @Test
     public void testSelect() {
         System.out.println(("----- 查询所有数据 ------"));
         List<Hotel> hotels = hotelMapper.selectList(null);//里面是查询条件
         for (int i=0;i<hotels.size();i++){
             System.out.println(hotels.get(i).toString());
         }
     }
 ​
 ​
     @Test
     public void testSelectById() {
         System.out.println(("----- 根据ID查询单条酒店数据 ------"));
         Hotel hotel = hotelMapper.selectById(609023);//里面是查询条件
         System.out.println(hotel);
     }
     @Test
     public void testSelectBathById() {
         System.out.println(("----- 根据ID查询多条酒店数据 ------"));
         List<Integer> IDList = Arrays.asList(648219, 672207, 5871652, 200214538);
         List<Hotel> hotels = hotelMapper.selectBatchIds(IDList);//里面是查询条件
         for (int i=0;i<hotels.size();i++){
             System.out.println(hotels.get(i).toString());
         }
     }
 ​
 ​
 ​
     @Test
     public void testSelectPagination() {
         System.out.println(("----- 分页查询所有数据 ------"));
         Page<Hotel> hotelPage = new Page<>(1 , 10 , false);//页面对象
         Page<Hotel> hotelPageNew = hotelMapper.selectPage(hotelPage, null);
         //记住 记住,记住 一定要去配分页拦截器去才可以生效,否则会把所有数据全部返回回来
         System.out.println("当前页码值"+hotelPageNew.getCurrent());
         System.out.println("每页显示数"+hotelPageNew.getSize());
         System.out.println("总共页数"+hotelPageNew.getPages());
         System.out.println("总共条数"+hotelPageNew.getTotal());
         System.out.println("页面数据"+hotelPageNew.getRecords());
     }
 ​
 ​
 ​
     @Test
     public void testSelectByQuery() {
         System.out.println(("----- 第一种一般条件查询 ------"));
         QueryWrapper wrapper=new QueryWrapper();
         wrapper.gt("price",1000);//价格大于800的约束
         List list = hotelMapper.selectList(wrapper);
         for (int i=0;i<list.size();i++){
             System.out.println(list.get(i).toString());
         }
 ​
     }
 ​
     @Test
     public void testSelectByQuery2() {
         System.out.println(("----- 第二种(lambma)的一般条件查询 ------"));
         QueryWrapper<Hotel> wrapper=new QueryWrapper<Hotel>();
         wrapper.lambda().le(Hotel::getPrice,400);//价格小于400的约束
         List<Hotel> List = hotelMapper.selectList(wrapper);
         for (int i=0;i<List.size();i++){
             System.out.println(List.get(i).toString());
         }
 ​
     }
 ​
     @Test
     public void testSelectByQueryMuti() {
         System.out.println(("----- 较为复杂的条件查询 ------"));
         QueryWrapper<Hotel> wrapper=new QueryWrapper<Hotel>();
         wrapper.lambda().le(Hotel::getPrice,800).like(Hotel::getName,"深圳");//表示和的情况不需要加and,但表示或的情况需要加or()
         List<Hotel> List = hotelMapper.selectList(wrapper);
         for (int i=0;i<List.size();i++){
             System.out.println(List.get(i).toString());
         }
 ​
     }
 ​
     @Test
     public void testSelectByQueryMuti2() {
         System.out.println(("----- 较为复杂的条件查询(更加规范与间接) ------"));
         LambdaQueryWrapper<Hotel> lqw=new LambdaQueryWrapper<Hotel>();
         lqw.le(Hotel::getPrice,800).like(Hotel::getName,"深圳");//表示和的情况不需要加and,但表示或的情况需要加or()
         List<Hotel> List = hotelMapper.selectList(lqw);
         for (int i=0;i<List.size();i++){
             System.out.println(List.get(i).toString());
         }
 ​
     }
 ​
 ​
 ​
     @Test
     public void testSelectByQueryMutiSwitch() {
         System.out.println(("----- 带有判断的条件查询 ------"));
         LambdaQueryWrapper<Hotel> lqw=new LambdaQueryWrapper<Hotel>();
         Hotel hotel1=new Hotel();
         hotel1.setCity("天津");
         lqw.lt(hotel1.getId()!=null,Hotel::getPrice,2000);//条件选择判断,先进行判断是否进行限制筛选
         lqw.gt(Hotel::getPrice,1500);
         List<Hotel> hotels = hotelMapper.selectList(lqw);
         for (int i=0;i<hotels.size();i++){
             System.out.println(hotels.get(i).toString());
         }
 ​
     }
 ​
 ​
     @Test
     public void testSelectMap() {
         System.out.println(("----- 带有投影的条件查询 ------"));
         LambdaQueryWrapper<Hotel> lqw=new LambdaQueryWrapper<Hotel>();
         lqw.select(Hotel::getName,Hotel::getPrice,Hotel::getBrand);//只查询name price brand这三个字段
         lqw.gt(Hotel::getPrice,1400);
         List<Hotel> hotels = hotelMapper.selectList(lqw);
         for (int i=0;i<hotels.size();i++){
             System.out.println(hotels.get(i).toString());
         }
 ​
     }
 ​
 ​
     @Test
     public void testSelectMap2() {
         System.out.println(("----- 带有group和count的投影条件查询 ------"));
         QueryWrapper<Hotel>qw=new QueryWrapper<Hotel>();
         qw.select("Count(*) as count , city");//按城市进行数量上的分类
         qw.groupBy("city");
         List<Map<String, Object>> maps = hotelMapper.selectMaps(qw);
         for (int i=0;i<maps.size();i++){
             System.out.println(maps.get(i));
         }
 ​
     }
 ​
 ​
 ​
 }
 ​

4.2 增添操作

 package com.example.mptest;
 ​
 import com.example.mptest.mapper.HotelMapper;
 import com.example.mptest.pojo.entity.Hotel;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 ​
 import java.util.ArrayList;
 import java.util.List;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:48
  */
 @SpringBootTest
 public class TestAdd {
 ​
     @Autowired
     private HotelMapper hotelMapper;
 ​
     @Test
     public void testAddSigal() {
         System.out.println(("----- 插入单条数据数据 ------"));
         Hotel hotel1=new Hotel(null,"天津唐拉雅秀国际酒店","和平路199号",999,47,"唐拉雅秀","天津","二钻","小白楼","40.10144","116.380641","https://m.tuniucdn.com/fb2/t1/G2/M00/C7/CB/Cii-T1km_5eICnpJAAHOWN1GylMAAKYJwF0Hp8AAc5w000_w200_h200_c1_t0.jpg",0,false);
         int insert = hotelMapper.insert(hotel1);
         System.out.println(insert);
     }
 ​
     @Test
     public void testAddMuti() {
         System.out.println(("----- 插入多条数据数据 ------"));
         Hotel hotel1=new Hotel(1999999l,"天津喜马拉雅快捷酒店","和平路133号",198,47,"喜马拉雅","天津","二钻","小白楼","40.10144","116.380641","https://m.tuniucdn.com/fb2/t1/G2/M00/C7/CB/Cii-T1km_5eICnpJAAHOWN1GylMAAKYJwF0Hp8AAc5w000_w200_h200_c1_t0.jpg",0,false);
         Hotel hotel2=new Hotel(1999992l,"天津四季酒店","和平路111号",1999,47,"唐拉雅秀","天津","二钻","小白楼","40.10144","116.380641","https://m.tuniucdn.com/fb2/t1/G2/M00/C7/CB/Cii-T1km_5eICnpJAAHOWN1GylMAAKYJwF0Hp8AAc5w000_w200_h200_c1_t0.jpg",0,false);
         Hotel hotel3=new Hotel(1999991l,"天津北国宾馆","和平路222号",799,47,"唐拉雅秀","天津","二钻","小白楼","40.10144","116.380641","https://m.tuniucdn.com/fb2/t1/G2/M00/C7/CB/Cii-T1km_5eICnpJAAHOWN1GylMAAKYJwF0Hp8AAc5w000_w200_h200_c1_t0.jpg",0,false);
         ArrayList hotelList=new ArrayList<Hotel>();
         hotelList.add(hotel1);
         hotelList.add(hotel2);
         hotelList.add(hotel3);
         boolean insert = hotelMapper.saveHotelsByNative(hotelList);
         System.out.println(insert);
 ​
     }
 ​
 ​
 ​
 ​
 }
 ​

4.3 删除操作

 package com.example.mptest;
 ​
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.example.mptest.mapper.HotelMapper;
 import com.example.mptest.pojo.entity.Hotel;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 ​
 import java.util.ArrayList;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:48
  */
 @SpringBootTest
 public class TestDelete {
 ​
     @Autowired
     HotelMapper hotelMapper;
 ​
     @Test
     public void testDeleteCommon() {
         System.out.println(("----- 根据ID删除单条数据------"));
         int i = hotelMapper.deleteById(2048047291L);
         System.out.println(i);
     }
 ​
     @Test
     public void testDeleteMuti() {
         System.out.println(("----- 根据ID删除多条数据------"));
         ArrayList hotelList=new ArrayList();
         hotelList.add(2048047291L);
         hotelList.add(727679);
         hotelList.add(1457521002);
         int i = hotelMapper.deleteBatchIds(hotelList);
         System.out.println(i);
     }
 ​
 ​
     @Test
     public void testDeleteByQuery() {
         System.out.println(("----- 根据查询删除单条数据------"));
         LambdaQueryWrapper<Hotel> lqt=new LambdaQueryWrapper<Hotel>();
         lqt.like(Hotel::getName,"深圳大中华");
         int i = hotelMapper.delete(lqt);
         System.out.println(i);
     }
 ​
 }
 ​

4.4 修改操作

 package com.example.mptest;
 ​
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.example.mptest.mapper.HotelMapper;
 import com.example.mptest.pojo.entity.Hotel;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 15:48
  */
 ​
 @SpringBootTest
 public class TestUpdate {
 ​
     @Autowired
     private HotelMapper hotelMapper;
 ​
 ​
     @Test
     public void testUpdate() {
         System.out.println(("----- 根据ID修改单条数据 ------"));
         Hotel hotel1=new Hotel();
         hotel1.setId(2056105938L);
         hotel1.setAddress("丽泽金融商务区凤凰路新址");
         int i = hotelMapper.updateById(hotel1);
         System.out.println(i);
     }
 ​
     @Test
     public void testUpdateMuti() {
         System.out.println(("----- 根据条件进行修改符合的数据 ------"));
         Hotel hotel1=new Hotel();
         hotel1.setPrice(1999);
         LambdaQueryWrapper<Hotel> lqw=new LambdaQueryWrapper<Hotel>();
         lqw.eq(Hotel::getCity,"天津");
         int i = hotelMapper.update(hotel1,lqw);//将成为为天津的酒店的价格统一为1999元
         System.out.println(i);
     }
 ​
 }
 ​

5. 开发实用技术点

5.1 分页查询

实现MP的分页查询功能,需要配置MP的分页拦截器增强功能

5.1.1 分页拦截器配置

在config包中创建一个MPConfig的类,实现一下代码

 package com.example.mptest.config;
 ​
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 19:38
  */
 @Configuration
 public class MybatisPlusConfig {
 ​
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor(){
         MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
         mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());//配置分页增强拦截器
         mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//配置乐观锁增强拦截器
         return mybatisPlusInterceptor;
     }
 ​
 }
 ​

5.1.2 分页功能实现

     @Test
     public void testSelectPagination() {
         System.out.println(("----- 分页查询所有数据 ------"));
         Page<Hotel> hotelPage = new Page<>(1 , 10 ,100true);//页面对象 分别是页面index和页面size和total和searchCount
         Page<Hotel> hotelPageNew = hotelMapper.selectPage(hotelPage, null);
         //记住 记住,记住 一定要去配分页拦截器去才可以生效,否则会把所有数据全部返回回来
         System.out.println("当前页码值"+hotelPageNew.getCurrent());
         System.out.println("每页显示数"+hotelPageNew.getSize());
         System.out.println("总共页数"+hotelPageNew.getPages());
         System.out.println("总共条数"+hotelPageNew.getTotal());
         System.out.println("页面数据"+hotelPageNew.getRecords());
     }
 ​

5.2 乐观锁问题

实现MP的乐观锁功能,需要配置MP的乐观锁拦截器增强功能和配置乐观锁字段

5.1.1 乐观锁拦截器配置

在config包中创建一个MPConfig的类,实现一下代码

 package com.example.mptest.config;
 ​
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 ​
 /**
  * @author M
  * @version 1.0
  * @description:
  * @date 2023/12/5 19:38
  */
 @Configuration
 public class MybatisPlusConfig {
 ​
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor(){
         MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
         mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());//配置分页增强拦截器
         mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());//配置乐观锁增强拦截器
         return mybatisPlusInterceptor;
     }
 ​
 }
 ​

5.1.2 乐观锁字段配置

 //在实体类中加入如下字段
     @Version
     private int version;//乐观锁的字段设置(注意需要去加拦截器)
 ​
 //就像下面一样
 ​
 ​
 @AllArgsConstructor
 @NoArgsConstructor
 @Setter
 @Getter
 @TableName("tb_hotel")
 public class Hotel {
 ​
     @TableId(type = IdType.ASSIGN_ID)
     private Long id;
     private String name;
     private String address;
     private double price;
     private int score;
     private String brand;
     private String city;
     private String starName;
     private String business;
     private String latitude;
     private String longitude;
     private String pic;
     @Version
     private int version;//乐观锁的字段设置(注意需要去加拦截器)
 ​
     @TableLogic(value = "0",delval = "1")//这个也可以在yml文件进行全局配置
     private int deleted;//软删除字段,0代表未删除,1代表已删除
 ​
     @TableField(exist = false)//代表数据库中没有这个字段
     private boolean status;
 ​
     
 }

5.1.3 乐观锁功能实现

     @Test
     public void testLock() {
         Hotel u1=hotelMapper.selectById(101176l);
         u1.setAge(77);
         int i = hotelMapper.updateById(u1);
         System.out.println(i);
         //乐观锁的原理是sql执行时会where检查此时的version和拿到的version对比
         //如果此时并发操作,version已经被修改了(增加),同时将要修改的version不一样了,则并发的第二条数据不会被执行
         //这样子:UPDATE user SET name=?, age=?, email=?, version=2 WHERE id=? AND version=1 AND deleted=0
     }

6. 总结

本实践没有过多的文本描述,多在代码中的注释。但通过此个实践了解学习之后,应该可以较好的掌握MP这套持久层开发解决方案,对于中小型项目,可以大幅提升开发效率

相关的配套实践Demo会上传Github开源,SQL文件也在上面

项目链接:Mybatis_Plus的全干货基础实践课程