MybatisPlus入门

1. MybatisPlus入门

1.1 快速入门

1.1.1 新建工程

新建模块,导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>mybatisplus_01_quickstart</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
	 <!-- mybaits plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <!-- druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>

        <!-- mysql数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- spring-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
1.1.2 导入数据库
create database if not exists mybatisplus_db character set utf8;
use mybatisplus_db;

DROP TABLE IF EXISTS user;

CREATE TABLE user (
            id bigint(20) primary key auto_increment,
            name varchar(32) not null,
            password  varchar(32) not null,
            age int(3) not null ,
            tel varchar(32) not null
);
insert into user values(null,'tom','123456',12,'12345678910');
insert into user values(null,'jack','123456',8,'12345678910');
insert into user values(null,'jerry','123456',15,'12345678910');
insert into user values(null,'tom','123456',9,'12345678910');
insert into user values(null,'snake','123456',28,'12345678910');
insert into user values(null,'张益达','123456',22,'12345678910');
insert into user values(null,'张大炮','123456',16,'12345678910');
1.1.3 新建实体类
package com.itheima.domain;

import lombok.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}
1.1.4 application.yml中配置Jdbc参数
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
    username: root
    password: root
1.1.5 定义数据接口,继承BaseMapper
package com.itheima.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao extends BaseMapper<User> {
}
1.1.6 测试类中注入dao接口,测试功能
package com.itheima;

import com.itheima.dao.UserDao;
import com.itheima.domain.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
class Mybatisplus01QuickstartApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }

}

1.2 MP简介

1.2.1 MyBatisPlus介绍
1.3.1 MyBatisPlus特性
  • 无侵入:只做增强不做改变,不会对现有工程产生影响。导入MP后也可以使用原生Mybatis
  • 强大的 CRUD 操作:内置通用 Mapper,少量配置即可实现单表CRUD 操作
  • 支持 Lambda:编写查询条件无需担心字段写错
  • 支持主键自动生成
  • 内置分页插件

2. 标准开发

2.1 CRUD

  • 已提供的通用Mapper内置的CRUD通用方法

    功能BaseMapper中提供方法备注
    新增int insert(T entity)
    根据id删除int deleteById(Serializable id)id类型不确定,但是都要实现序列化接口
    根据id修改int updateById(@Param("et") T entity)按需修改,动态SQL
    根据id查询T selectById(Serializable id)
    查询所有List<T> selectList(Wrapper<T> queryWrapper)
    分页查询Ipage<E> selectPage(Ipage<E> page,null)
    条件查询Ipage<E> selectPage(Ipage<E> page, Wrapper<T> queryWrapper)
  • 演示代码

    package com.itheima;
    
    import com.itheima.dao.UserDao;
    import com.itheima.domain.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
    class Mybatisplus01QuickstartApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void testSave() {
            User user = new User();
            user.setName("黑马程序员");
            user.setPassword("itheima");
            user.setAge(12);
            user.setTel("4006184000");
            userDao.insert(user);
        }
    
        @Test
        void testDelete() {
            userDao.deleteById(1401856123725713409L);
        }
    
        @Test // 已经实现了按需更新
        void testUpdate() {
            User user = new User();
            user.setId(1L);
            user.setName("Tom888");
            user.setPassword("tom888");
            userDao.updateById(user);
        }
    
        @Test
        void testGetById() {
            User user = userDao.selectById(2L);
            System.out.println(user);
        }
    
    
        @Test
        void testGetAll() {
            List<User> userList = userDao.selectList(null);
            System.out.println(userList);
        }
    }
    

3. 查询

3.1 分页查询

3.1.1 实现
  • 已提供的通用Mapper内置的分页查询方法

    功能BaseMapper中提供方法备注
    分页查询Ipage<E> selectPage(Ipage<E> page,null)
    条件查询Ipage<E> selectPage(Ipage<E> page, Wrapper<T> queryWrapper)

  • 演示代码

    装配分页拦截器作为Spring管理的bean

    package com.itheima.config;
    
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MybatisPlusConfig {
        
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            //1 创建MybatisPlusInterceptor拦截器对象
            MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
            //2 添加分页拦截器
            mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return mpInterceptor;
        }
    }
    

    执行分页查询

    //分页查询
    @Test
    void testSelectPage(){
        //1 创建IPage分页对象,设置分页参数
        IPage<User> page=new Page<>(1,3);
        //2 执行分页查询
        userDao.selectPage(page,null);
        //3 获取分页结果
        System.out.println("当前页码值:"+page.getCurrent());
        System.out.println("每页显示数:"+page.getSize());
        System.out.println("总页数:"+page.getPages());
        System.out.println("总条数:"+page.getTotal());
        System.out.println("当前页数据:"+page.getRecords());
    }
    
3.1.2 常见问题
  • 问题描述

    使用该插件过程中,常见的问题是总记录数为0。

    为0是最容易发现的,其实还有其他问题

    • 不是分页查询,而是查了所有记录
    • SQL语句中没有添加分页条件

    等等。

  • 原因

    分页拦截器,未配置或者配置错误。

  • 解决方法

    见3.1.1中装配分页拦截器作为Spring管理的bean

3.2 开启MyBatisPlus日志

3.2.1 开启日志
# 开启mp的日志(输出到控制台)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.2.2 简化日志(不推荐)
3.2.2.1 取消初始化spring日志打印
  • 原日志显示如下:
    在这里插入图片描述

  • 取消做法

    resources下新建一个logback.xml文件,名称固定,内容为空,如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    
    </configuration>
    

    关于logback参考播客:https://www.jianshu.com/p/75f9d11ae011

3.2.3.1 取消SpringBoot启动banner图标
  • 原日志显示如下:

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::                (v2.5.0)
    
  • 取消做法

    spring:
      main:
        banner-mode: off # 关闭SpringBoot启动图标(banner)
    
3.4.3 取消MybatisPlus启动banner图标
  • 原日志显示如下:

     _ _   |_  _ _|_. ___ _ |    _ 
    | | |\/|_)(_| | |_\  |_)||_|_\ 
         /               |         
                            3.4.1 
    
  • 取消做法

    mybatis-plus:
      global-config:
        banner: off # 关闭mybatisplus启动图标
    

3.3 条件构造器QueryWrapper

  • MyBatisPlus将书写复杂的SQL条件进行了封装,使用编程的方式完成查询条件的组合
  • 所有的查询条件封装在QueryWrapper对象中,并且在调用通用方法时传递该对象

简单的查询,建议使用QueryWrapper;复杂的SQL语句,不推荐使用;

3.3.1 条件构造器封装方式
  1. 按条件查询

    手写字段名,字段名容易写错

    //方式一:按条件查询
    QueryWrapper<User> qw=new QueryWrapper<>();
    // 设置条件,参数分为为字段名和值
    // lt : less then 小于
    qw.lt("age", 18);
    List<User> userList = userDao.selectList(qw);
    System.out.println(userList);
    
  2. lambda格式按条件查询

    可以避免字段名写错

    //方式二:lambda格式按条件查询
    QueryWrapper<User> qw = new QueryWrapper<User>();
    User user /* = 获取一个user对象*/;
    qw.lambda().lt(User::getName,user.getName());
    List<User> userList = userDao.selectList(qw);
    System.out.println(userList);
    
  3. lambda格式按条件查询(推荐)

    //方式三:lambda格式按条件查询
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    // LambdaQueryWrapper支持链式编程
    lqw.lt(User::getAge, 10);
    // qw.lambda().lt(User::getName,user.getName());
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);
    
3.3.2 组合条件
  1. 并且关系(and)

    设置条件时默认是并且关系

    // 并且关系,默认就是并且关系
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    //10到30岁之间
    lqw.lt(User::getAge, 30).gt(User::getAge, 10);
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);
    
  2. 或者关系(or)

    // 或者关系,需要通过or()方法连接
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    / 小于10岁或者大于30岁
    lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);
    
3.3.3 QueryWrapper方法与功能
  • 常用方法

    方法功能备注
    eq指定列的值相同equals的简写
    ne指定列的值不相同not equals的简写
    lt指定列的值小于less then的简写
    le指定列的值小于等于less then and equals的简写
    gt指定列的值大于great then 的简写
    ge指定列的值大于等于great then and equals的简写
    between指定列的值在…和…之间
    notBetween指定列的值不在…和…之间
    like指定列的值等值模糊查询
    notLIke指定列的值不等值模糊查询
    orderByAsc按照指定的列升序排序
    orderByDesc按照指定的列降序排序
    groupBy按照指定的列分组
    having按照指定的列在分组后条件过滤
    in单条件多值查询
    isNull指定列的值为空
    isNOtNull指定列的值不为空
  • 用户登录(eq匹配)

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//等同于=
lqw.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
User loginUser = userDao.selectOne(lqw);
System.out.println(loginUser);
  • 购物设定价格区间、户籍设定年龄区间(le ge匹配 或 between匹配)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//范围查询 lt le gt ge eq between
lqw.between(User::getAge, 10, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
  • 查信息,搜索新闻(非全文检索版:like匹配)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//模糊匹配 like
lqw.likeLeft(User::getName, "J");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
  • 统计报表(分组查询聚合函数)
QueryWrapper<User> qw = new QueryWrapper<User>();
qw.select("gender","count(*) as nums");
qw.groupBy("gender");
List<Map<String, Object>> maps = userDao.selectMaps(qw);
System.out.println(maps);

官方API文档

3.3.4 NULL值处理

在多条件查询中,有条件的值为空会影响查询结果?
在这里插入图片描述

3.3.4.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);
3.3.4.2 QueryWrapper判空
  • 准备查询参数封装对象

    @Data
    public class User {
        private Long id;
        private String name;
        private String password;
        private Integer age;
        private String tel;
        private Integer online;
    }
    
    @Data
    public class UserQuery extends User {
        private Integer age2;
    }
    
  • 测试类中,使用QueryWrapper判空

    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    //先判定第一个参数是否为true,如果为true连接当前条件
    //lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2());
    //lqw.gt(null != uq.getAge(),User::getAge, uq.getAge());
    // 链式编程
    lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2())
       .gt(null != uq.getAge(),User::getAge, uq.getAge());
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);
    

3.4 查询投影

查询投影,就是要查询的列的问题。可能存在

  • 只查询表中存在的部分字段,
  • 或者查询表中没有的字段(聚合查询)

复杂查询不推荐使用QueryWrapper,使用Mybatis原生方式,自己编写SQL。

3.4.1 查询结果包含模型类中部分属性
/*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");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
3.4.2 查询结果包含模型类中未定义的属性
QueryWrapper<User> lqw = new QueryWrapper<User>();
// count(*)不存在于表结构中国的字段
lqw.select("count(*) as count, tel");
lqw.groupBy("tel");
List<Map<String, Object>> userList = userDao.selectMaps(lqw);
System.out.println(userList);

3.5 字段映射与表名映射

3.5.1 问题一:表字段与实体属性名不一致
  • 在模型类属性上方,使用@TableField属性注解,通过==value==属性,设置当前属性对应的数据库表中的字段关系。
    在这里插入图片描述
3.5.2 问题二:实体类中添加了数据库中不存在的字段
  • 在模型类属性上方,使用@TableField注解,通过**exist**属性,设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用。

    查询和增删改的时候,都不会参与数据库的操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JNvE2GaD-1655171079951)(07-MybatisPlus-课堂笔记59.assets/image-20210801182809131.png)]

3.5.3 问题三:不参与查询
  • 在模型类属性上方,使用@TableField注解,通过**select**属性:设置该属性是否参与默认查询(select * )。此属性与select()映射配置不冲突。
    在这里插入图片描述
4.4 问题四:表名与实体类名不同步
  • 模型类上方,使用**@TableName注解,通过value**属性,设置当前类对应的数据库表名称。
    在这里插入图片描述
@Data
@TableName("tbl_user")
public class User {
    /*
        id为Long类型,因为数据库中id为bigint类型,
        并且mybatis有自己的一套id生成方案,生成出来的id必须是Long类型
     */
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false) // 仅仅是不参与查询
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false) //表示online字段不参与CRUD操作
    private Boolean online;
}

4. 增删改DML

4.1 增:主键生成策略

4.1.1 不同的表的id生成策略不同
  • 日志:自增(1,2,3,4,……)
  • 购物订单:特殊规则(FQ23948AK3843)
  • 外卖单:关联地区日期等信息(10 04 20200314 34 91)
  • 关系表:可省略id
  • ……
4.1.2 MybatisPlus支持的生成策略
4.1.2.1MybatisPlus支持8种生成策略
  • 五种可用,三种已过期。详情如下:

    public enum IdType {
        /**
         * 数据库ID自增
         * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
         */
        AUTO(0),
        /**
         * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
         */
        NONE(1),
        /**
         * 用户输入ID
         * <p>该类型可以通过自己注册自动填充插件进行填充</p>
         */
        INPUT(2),
    
        /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
        /**
         * 分配ID (主键类型为number或string),
         * 默认使用com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator(雪花算法)
         *
         * @since 3.3.0
         */
        ASSIGN_ID(3),
        /**
         * 分配UUID (主键类型为 string)
         * 默认使用 com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
         */
        ASSIGN_UUID(4),
        /**
         * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
         */
        @Deprecated
        ID_WORKER(3),
        /**
         * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
         */
        @Deprecated
        ID_WORKER_STR(3),
        /**
         * @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
         */
        @Deprecated
        UUID(4);
    }
    
4.1.2.2 用法1:逐个主键指定
  • 使用注解@TableId

    • 名称:@TableId

    • 类型:属性注解

    • 位置:模型类中用于表示主键的属性定义上方

    • 作用:设置当前类中主键属性的生成策略

    • 相关属性

      type:设置主键属性的生成策略,值参照IdType枚举值

在这里插入图片描述

4.1.2.3 全局配置策略
  • application.yaml

    mybatis-plus:
      global-config:
        db-config:
          id-type: assign_id # 全局使用雪花算法生成主键
          table-prefix: tbl_ # 全局指定表名前缀,实体类上就不需要添加@TableName()注解了
    

4.2删

4.2.1 按照主键删除批量删除
//删除指定多条数据
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);

userDao.deleteBatchIds(list);
4.2.2 根据主键查询多条记录
//查询指定多条数据
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
4.2.3 逻辑删除(Delete/Update)
4.2.3.1 概念

在实际环境中,如果想删除一条数据,是否会真的从数据库中删除该条数据?

  • 删除操作业务问题:业务数据从数据库中丢弃

  • 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中
    在这里插入图片描述

4.2.3.2 实现
  1. 数据库表中添加逻辑删除标记字段
    在这里插入图片描述

  2. 实体类中添加对应成员变量,并(逐个指定)标记对应属性

    package com.itheima.domain;
    
    import com.baomidou.mybatisplus.annotation.*;
    
    import lombok.Data;
    
    @Data
    public class User {
    
        private Long id;
        
        //逻辑删除字段,标记当前记录是否被删除
        // value表示未删除,delval表示已删除
        @TableLogic(value="0", delval="1")
        private Integer deleted;
        
    }
    
  3. 实体类中添加成员变量后,也可以全局配置

    mybatis-plus:
      global-config:
        db-config:
          table-prefix: tbl_
          # 逻辑删除字段名
          logic-delete-field: deleted
          # 逻辑删除字面值:未删除为0
          logic-not-delete-value: 0
          # 逻辑删除字面值:删除为1
          logic-delete-value: 1
    
4.2.3.3 本质及查询

逻辑删除本质:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。
在这里插入图片描述

4.3 改:乐观锁

4.3.1 概念
  • 概念

    乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不用上锁。只在更新的时候会判断一下在此期间别人有没有去更新这个数据。

  • 实现思路

    使用数据版本(Version)记录

    • 这最常用的一种实现方式。为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 version字段来实现。
    • 当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。
    • 当提交更新的时候,判断数据库表对应记录的当前版本信息取出来的version值进行比对,如果数据库表当前版本号与之前取出来的version值相等,则予以更新,否则认为是过期数据。

    CAS:Compare And Swap

    使用时间戳记录
    在这里插入图片描述

4.3.2 实现
  1. 数据库表中添加锁标记字段
    在这里插入图片描述

  2. 实体类中添加对应字段,并设定当前字段为版本字段

    package com.itheima.domain;
    
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableLogic;
    import com.baomidou.mybatisplus.annotation.Version;
    import lombok.Data;
    
    @Data
    public class User {
    
    	private Long id;
    	
        @Version
        private Integer version;
    }
    
    
  3. 配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

    package com.itheima.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;
    
    @Configuration
    public class MpConfig {
        @Bean
        public MybatisPlusInterceptor mpInterceptor() {
            //1.定义Mp拦截器
            MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
    
            //2.添加乐观锁拦截器
            mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            
            return mpInterceptor;
        }
    }
    
    
  4. 使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行

    @Test
    public void testUpdate() {
        /*User user = new User();
        user.setId(3L);
        user.setName("Jock666");
        user.setVersion(1);
        userDao.updateById(user);*/
        
        //1.先通过要修改的数据id将当前数据查询出来
        //User user = userDao.selectById(3L);
        //2.将要修改的属性逐一设置进去
        //user.setName("Jock888");
        //userDao.updateById(user);
        
        //1.先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(3L);     //version=3
        User user2 = userDao.selectById(3L);    //version=3
        user2.setName("Jock aaa");
        userDao.updateById(user2);              //version=>4
        user.setName("Jock bbb");
        userDao.updateById(user);               //verion=3?条件还成立吗?
    }
    

在这里插入图片描述

5. 代码生成

or = new MybatisPlusInterceptor();

       //2.添加乐观锁拦截器
       mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
       
       return mpInterceptor;
   }

}






4. **使用乐观锁机制在修改前必须先获取到对应数据的`verion`方可正常进行**

```java
@Test
public void testUpdate() {
    /*User user = new User();
    user.setId(3L);
    user.setName("Jock666");
    user.setVersion(1);
    userDao.updateById(user);*/
    
    //1.先通过要修改的数据id将当前数据查询出来
    //User user = userDao.selectById(3L);
    //2.将要修改的属性逐一设置进去
    //user.setName("Jock888");
    //userDao.updateById(user);
    
    //1.先通过要修改的数据id将当前数据查询出来
    User user = userDao.selectById(3L);     //version=3
    User user2 = userDao.selectById(3L);    //version=3
    user2.setName("Jock aaa");
    userDao.updateById(user2);              //version=>4
    user.setName("Jock bbb");
    userDao.updateById(user);               //verion=3?条件还成立吗?
}

5. 代码生成

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值