MybatisPlus

MybatisPlus

基于狂神mybatisplus自整理笔记,可寻找对应视频参考该文章

通用mapper,和mybatisplus的区别

在这里插入图片描述

官网简介

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

官网-快速入门

https://baomidou.com/guide/quick-start.html#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B7%A5%E7%A8%8B

创建数据库
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);
idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com
插入对应的数据
DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
创建工程

这里可以创建一个springboot的工程,也可以是一个maven工程

初始化一个springboot的项目

<!--    导入依赖
          mybatisplus的依赖
          连接数据库的依赖
          单元测试的依赖
     -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
  </dependency>

  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
  </dependency>

  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
  </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.0.5</version>
  </dependency>
连接数据库
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
-----------------------------------------------------------------------------------
# 数据库的连接信息
spring:
datasource:
# 这个顺序不讲究
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
pojo
package com.qr.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

private long id;
private String name;
private Integer age;
private String email;

}
mapper

执行过程中

当我在将这个mapper和这个Repository全部都给注释掉会后

只要在启动类上能够扫描到该接口,改接口中的还是会放到容器中的

所以这两个可以省略,只要添加了MapScan

//表示是一个mapper接口,放到容器中
//@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {

}

启动

@SpringBootApplication
@MapperScan("com.qr.mapper")
public class MybatisplusTestApplication {

public static void main(String[] args) {
  SpringApplication.run(MybatisplusTestApplication.class, args);
}

}
测试
import com.qr.pojo.User;
import com.qr.mapper.UserMapper;
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 MybatisplusTestApplicationTests {

@Autowired
private UserMapper userMapper;

@Test
void contextLoads() {
  //查询全部,wrapper是一个条件构造器
  List<User> users = userMapper.selectList(null);
  users.forEach(System.out::println);
}

}

crud

添加
/*
添加
*/
@Test
void insert(){
//参数需要一个对象
User user = new User();
/*
  如果使用的lombok中生成的方法,那么导入maven后,idea中还是需要添加插件的
  不然不会存在相应的方法
*/
user.setName("zhangsan");
user.setAge(22);
user.setEmail("357886376");
userMapper.insert(user);


}

因为我的数据库第一遍添加的时候没有选择id,但是是自动生成到了0号位置
在这里插入图片描述

此时再次添加其他数据的时候会出现下面的异常

    @Test
    void insert(){
        //参数需要一个对象
        //User user = new User();
        /*
            如果使用的lombok中生成的方法,那么导入maven后,idea中还是需要添加插件的
            不然不会存在相应的方法
         */
        /*user.setName("zhangsan");
        user.setAge(22);
        user.setEmail("357886376");
        userMapper.insert(user);
*/
        //这个社会的顺序是讲究的
        User user1 = new User();
        user1.setName("lisi");
        user1.setAge(2);
        user1.setEmail("hfhasjfas");
        userMapper.insert(user1);
    }
==========================================================================================
org.springframework.dao.DuplicateKeyException: 
### Error updating database.  Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'user.PRIMARY'
### The error may involve com.qr.mapper.UserMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO user  ( id, name, age, email )  VALUES  ( ?, ?, ?, ? )
### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'user.PRIMARY'
; Duplicate entry '0' for key 'user.PRIMARY'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'user.PRIMARY'

查看我们的表中,我们的主键是非空且唯一的

mysql在批量插入数据的时候,如果有一个字段具有unique约束,而插入数据重复的话,

就会抛出DuplicateKeyException导致后续数据无法插入

主键没有设置,这里可以选择点击自增来完成,或者自己设置一个表中没有主键字段

SQLIntegrityConstraintViolationException: Duplicate entry xxx for key 这个错误,
这个错误的意思是:违反唯一约束条件,也即该字段设置是唯一的,但是数据插入时,报错相同记录的数据
在这里插入图片描述

User user1 = new User();
user1.setId(6);
user1.setName("lisi");
user1.setAge(2);
user1.setEmail("hfhasjfas");
userMapper.insert(user1);

当设置主键不冲突之后,就可以正常插入了

一般在SQL中我们的主键也因该是自增的,那么我们也可以执行SQL修改主键为自增的策略

??? 执行不了

ALTER TABLE USER MODIFY id INT AUTO_INCREMENT PRIMARY KEY;

ALTER TABLE USER ADD id INT AUTO_INCREMENT;

???

修改不了我重新创建
DROP TABLE IF EXISTS USER;

CREATE TABLE USER
(
	id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
	NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);
修改实体类完成

给实体类添加相应的注解来完成主键的增长

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

/**
   * @TableId是一个枚举类:
   *     AUTO(0),主键自增,这个配置要求数据库也是自增的
   *     NONE(1),不使用自增
   *     INPUT(2),手动输入
   *     ID_WORKER(3),全局唯一id
   *     UUID(4),全局唯一id
   *     ID_WORKER_STR(5);全局唯一字符串
   */
  @TableId(type = IdType.ID_WORKER)
  private long id;
  private String name;
  private Integer age;
  private String email;

}
删除
	 /**
   * 删除
   */
  @Test
  void delete(){
      int i = userMapper.deleteById(1L);
      System.out.println(i);
  }

  /**
   * 批量删除
   */
  @Test
  void testDeletePiliang(){
      int i = userMapper.deleteBatchIds(Arrays.asList(2, 3));
      System.out.println(i);
  }
逻辑删除

物理删除:直接删除

逻辑删除:变量查询,查询不到,防止数据的丢失

给数据库中字段添加一列isdelete

ALTER TABLE USER ADD COLUMN is_delete INT DEFAULT 0;

实体类中添加对用的属性

/**
* @TableLogic逻辑删除
*/
@TableLogic
private Integer isDelete;

添加逻辑删除组件

import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//管理事务
@EnableTransactionManagement
//可以将MapScan挪到这里,因为这里是MybatisPlus的配置类,让这里去扫描
@Configuration
public class MybatisPlusConfig {
  //注册乐观锁插件
  @Bean
  public OptimisticLockerInterceptor optimisticLockerInterceptor() {
      return new OptimisticLockerInterceptor();
  }

  /**
   * 分页插件
   * @return
   */
  @Bean
  public PaginationInterceptor paginationInterceptor() {
      return new PaginationInterceptor();
  }

  /**
   * 逻辑删除
   */
  @Bean
  public ISqlInjector sqlInjector(){
      return new LogicSqlInjector();
  }
}

配置yml

# 数据库的连接信息
spring:
  datasource:
    # 这个顺序不讲究
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

测试,再次删除数据,看is_delete的值

在这里插入图片描述

修改
/**
* 修改
*/
@Test
void update(){
  User user = new User();
  user.setId(2L);
  user.setName("hello");
  user.setAge(12);
  user.setEmail("8888888888");
  userMapper.updateById(user);

}
查找
	/*
  查询
*/
@Test
void select(){
  User user = userMapper.selectById(1L);
  System.out.println(user);
}
分页查询

首先配置分页的拦截器

//管理事务
@EnableTransactionManagement
//可以将MapScan挪到这里,因为这里是MybatisPlus的配置类,让这里去扫描
@Configuration
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
  return new OptimisticLockerInterceptor();
}

/**
   * 分页插件
   * @return
   */
  @Bean
  public PaginationInterceptor paginationInterceptor() {
      return new PaginationInterceptor();
  }
}

这里面就自带了一个分页对象

/**
   * 测试分页插件
   */
  @Test
  void testPage(){
      /**
       * 参数1,当前也,参数2,页面的大小
       */
      Page<User> page = new Page<>(1, 2);
      userMapper.selectPage(page,null);
      page.getRecords().forEach(System.out::println);
      //总共几条记录
      System.out.println(page.getTotal());
  }
自动填充:
Mysql中的日期类型

Mysql中经常用来存储日期的数据类型有三种:Date、Datetime、Timestamp。
【1】Date数据类型:用来存储没有时间的日期。Mysql获取和显示这个类型的格式为“YYYY-MM-DD”。支持的时间范围为“1000-00-00”到“9999-12-31”。
【2】Datetime类型:存储既有日期又有时间的数据。存储和显示的格式为 “YYYY-MM-DD HH:MM:SS”。支持的时间范围是“1000-00-00 00:00:00”到“9999-12-31 23:59:59”。
【3】Timestamp类型:也是存储既有日期又有时间的数据。存储和显示的格式跟Datetime一样。支持的时间范围是“1970-01-01 00:00:01”到“2038-01-19 03:14:07”
原文链接:https://blog.csdn.net/qq_35860138/article/details/88957739

对于表的创建时间和修改时间应该是自动的添加到表当中的,而不是我们每次都要手动的设置

给数据库和实体类添加相应的字段

ALTER TABLE USER ADD COLUMN create_Time TIMESTAMP;
ALTER TABLE USER ADD COLUMN update_Time TIMESTAMP;

在这里插入图片描述

实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    /**
     * @TableId是一个枚举类:
     *     AUTO(0),主键自增,这个配置要求数据库也是自增的
     *     NONE(1),不使用自增
     *     INPUT(2),手动输入
     *     ID_WORKER(3),全局唯一id
     *     UUID(4),全局唯一id
     *     ID_WORKER_STR(5);全局唯一字符串
     */
    @TableId(type = IdType.AUTO)
    private long id;
    private String name;
    private Integer age;
    private String email;
    /**
     * 创建时间
     *      DEFAULT,默认不操作
     *      INSERT,填充策略,插入时触发
     *      UPDATE,更新时触发
     *      INSERT_UPDATE;插入更新都触发
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //修改时间
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;
    
}
处理器处理
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;

/**
* 日期处理器
*/
@Slf4j
@Component
public class MyDateHandler implements MetaObjectHandler {

  /**
   * 插入时的填充策略
   * @param metaObject
   */
  @Override
  public void insertFill(MetaObject metaObject) {
      log.info("start insert fill ....");
      /**
       * 参数:
       *      1:给哪个字段插入值
       *      2:更新时间
       *      3:创建时间
       */
      this.setFieldValByName("createTime", new Date(), metaObject);
      this.setFieldValByName("updateTime", new Date(), metaObject);
  }

  /**
   * 更新时的填充策略
   * @param metaObject
   */
  @Override
  public void updateFill(MetaObject metaObject) {
      log.info("start update fill ....");
      this.setFieldValByName("updateTime", new Date(), metaObject);
  }
}
插入测试

这个类加入到spring容器中就可以了

	@Test
 void insert(){
     User user1 = new User();
     user1.setName("zhaoliu");
     user1.setAge(22);
     user1.setEmail("hfhasjfas");
     userMapper.insert(user1);
 }

这样就可以插入成功,而且显示日期,由于表是重新创建的没有插入数据,所以是1
在这里插入图片描述

条件构造器

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qr.mapper.UserMapper;
import com.qr.pojo.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;
import java.util.Map;

@SpringBootTest
public class WrapperTests {

    @Autowired
    private UserMapper userMapper;
    /**
     * 条件构造器的使用
     * SELECT * FROM USER WHERE NAME IS NOT NULL AND email IS NOT NULL AND age > 15;
     */
    @Test
    void selectWrapper(){
        //参数需要一个Wrapper<User>
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //构造条件,name,email这列不为空,age>15岁的人
        wrapper.isNotNull("name").isNotNull("email").
                ge("age",15);
        userMapper.selectList(wrapper).forEach(System.out::println);
    }

    @Test
    void selectNameWrapper(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //select * from user where name = sandy
        wrapper.eq("name","Sandy");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

    /**
     * SELECT * FROM USER WHERE age BETWEEN 15 AND 20;
     */
    @Test
    void betweenWrapper(){
        //查询年龄范围
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age", 15, 20);
        Integer integer = userMapper.selectCount(wrapper);
        System.out.println(integer);
    }

    /**
     * 模糊查询
     */
    @Test
    void selectMohu(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        /**
         * 查询name中包含s的
         * email中左边以t开头的
         * name中右边以e结尾的
         */
        wrapper.notLike("name","s")
                .likeLeft("email","t")
                .likeRight("name","e");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

    /**
     * 连接查询
     *      SELECT * FROM USER WHERE age IN (SELECT age FROM USER WHERE age > 15);
     */
    @Test
    void selectInner(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.inSql("age","select age from user where age>15");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }

    /**
     * 排序
     *      SELECT * FROM USER ORDER BY age DESC;
     */
    @Test
    void selectSort(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("age");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

代码生成器

添加依赖
<dependency>
   <groupId>org.apache.velocity</groupId>
   <artifactId>velocity-engine-core</artifactId>
   <version>2.3</version>
</dependency>
编写代码生成器逻辑
package com.qr;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

/**
 * 代码生成器
 *      1:构建代码生成器对象
 *      2:配置策略
 *
 *
 */
public class CodeSoEasy {
    public static void main(String[] args) {
        //构建代码生成器对象
        AutoGenerator mpg = new AutoGenerator();

        //全局配置
        GlobalConfig gc = new GlobalConfig();
        //获取当前项目的路径
        String projectPath = System.getProperty("user.dir");
        //设置生成代码的输出路径
        gc.setOutputDir(projectPath+"/src/main/java");
        //设置作者
        gc.setAuthor("穷人");
        //是否打开资源管理器,不打开
        gc.setOpen(false);
        //是否覆盖原来生成的代码
        gc.setFileOverride(false);
        //去掉service的I前缀
        gc.setServiceName("%sService");
        //设置主键的生成策略
        gc.setIdType(IdType.ID_WORKER);
        //设置日期类型
        gc.setDateType(DateType.ONLY_DATE);
        //是否配置swagger文档
        gc.setSwagger2(true);

        //将全局配置丢入到自动生成器当中
        mpg.setGlobalConfig(gc);

        //设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        //设置使用数据库的驱动
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //设置包的配置
        PackageConfig pc = new PackageConfig();
        //设置模块名称
        pc.setModuleName("erp");
        //设置类路径
        pc.setParent("com.qr");
        //设置实体类的名称
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //策略配置
        //创建策略配置对象
        StrategyConfig strategy = new StrategyConfig();
        //设置要映射的表名
        strategy.setInclude("user");
        //设置包命名的规则,下划线转驼峰命名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //列名也支持下划线转驼峰
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //自动生成Lombok
        strategy.setEntityLombokModel(true);
        //逻辑删除的名称
        strategy.setLogicDeleteFieldName("deleted");
        //设置字段自动填充
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        //将自动填充的策略进行添加
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        //参数是一个list,需要创建一个list
        strategy.setTableFillList(tableFills);

        //乐观锁配置
        strategy.setVersionFieldName("version");
        //开启restful的驼峰命名
        strategy.setRestControllerStyle(true);
        //将网站url变为带下划线的形式
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        //执行代码
        mpg.execute();
    }
}

MybatisPlus乐观锁

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

使用方式:字段上加上@Version注解

给表中字段添加一个version

version中默认值设为1

ALTER TABLE USER MODIFY COLUMN VERSION INT DEFAULT 1;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

  /**
   * @TableId是一个枚举类:
   *     AUTO(0),主键自增,这个配置要求数据库也是自增的
   *     NONE(1),不使用自增
   *     INPUT(2),手动输入
   *     ID_WORKER(3),全局唯一id
   *     UUID(4),全局唯一id
   *     ID_WORKER_STR(5);全局唯一字符串
   */
  @TableId(type = IdType.AUTO)
  private long id;
  private String name;
  private Integer age;
  private String email;
  /**
   * 创建时间
   *      DEFAULT,默认不操作
   *      INSERT,填充策略,插入时触发
   *      UPDATE,更新时触发
   *      INSERT_UPDATE;插入更新都触发
   */
  @TableField(fill = FieldFill.INSERT)
  private Date createTime;
  //修改时间
  @TableField(fill = FieldFill.UPDATE)
  private Date updateTime;

  /**
   * 数据库字段同步实体类
   * @Version代表这个是mybatisplus的一个乐观锁的注解
   */
  @Version
  private Integer version;

}
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//管理事务
@EnableTransactionManagement
//可以将MapScan挪到这里,因为这里是MybatisPlus的配置类,让这里去扫描
@Configuration
public class MybatisPlusConfig {
  //注册乐观锁插件
  /**
   * 旧版
   */
  @Bean
  public OptimisticLockerInterceptor optimisticLockerInterceptor() {
      return new OptimisticLockerInterceptor();
  }
}

这样设置之后啥也不用管,直接测试

	@Test
  void testOptimisticLockerInnerInterceptor(){
      User user = userMapper.selectById(1L);
      user.setName("Mybatisplus");
      user.setAge(22);
      user.setEmail("357886376");
      userMapper.updateById(user);
  }

这样之后查看数据库版本信息就会发生相应的变化
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值