0
点赞
收藏
分享

微信扫一扫

【谷粒学院】002-Mybatis Plus:主键策略、实现自动填充、乐观锁


目录

​​一、主键策略​​

​​1、ID_WORKER​​

​​2、自增策略​​

​​3、其它主键策略​​

​​二、实现自动填充​​

​​1、根据Id更新操作​​

​​2、自动填充​​

​​数据库表中添加自动填充字段:​​

​​数据库表中添加create_time和update_time两个字段:​​

​​实体上添加注解:​​

​​创建类,实现MetaObjectHandler接口:​​

​​添加一条数据:​​

​​神奇的事情发生了:​​

​​注意:​​

​​三、乐观锁​​

​​1、什么是乐观锁​​

​​2、什么叫丢失更新​​

​​3、使用Mybatis Plus实现乐观锁​​

​​主要适用场景:​​

​​乐观锁实现方式:​​

​​步骤:​​

​​(1)在数据库中添加version字段:​​

​​(2)在实体类添加version字段,并添加 @Version 注解​​

​​(3)使用元对象处理器接口添加version的insert默认值​​

​​(4)在 MybatisPlusConfig 中注册 Bean​​

​​(5)测试乐观锁插件​​

一、主键策略

1、ID_WORKER

MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID;

参考资料:分布式系统唯一ID生成方案汇总:​​分布式系统唯一ID生成方案汇总 - nick hao - 

(自动增长、UUID、redis实现、Mybatis Plus自带策略(snowflake雪花算法))

#主键随机生成策略 #主键策略

2、自增策略

要想主键自增需要配置如下主键策略:

①需要在创建数据表的时候设置主键自增;

②实体字段中配置 @TableId(type = IdType.AUTO);

@TableId(type = IdType.AUTO)
private Long id;

要想影响所有实体的配置,可以设置全局主键配置:

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

3、其它主键策略

(分析 IdType 源码可知)

@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),

/**
* 该类型为未设置主键类型
*/
NONE(1),

/**
* 用户输入ID
* 该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),

/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),

/**
* 全局唯一ID (UUID)
*/
UUID(4),

/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);

private int key;

IdType(int key) {
this.key = key;
}
}

二、实现自动填充

1、根据Id更新操作

注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?

package com.zibo.mybatisplus;

import com.zibo.mybatisplus.entity.User;
import com.zibo.mybatisplus.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
public class MybatisPlusApplicationTests {

//注意:
//IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。
//为了避免报错,可以在 dao 层 的接口上添加 @Repository 注解
@Autowired
private UserMapper userMapper;

//查询操作
@Test
public void contextLoads() {
System.out.println(("----- selectAll method test ------"));
//UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper
//所以不填写就是无任何条件
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

//添加操作
@Test
public void add(){
//组织user对象
User user = new User();
user.setName("zibo");
user.setAge(24);
user.setEmail("18838186892@163.com");
//添加到数据库
int insert = userMapper.insert(user);
System.out.println("insert:" + insert);//影响的行数
System.out.println(user);//id自动回填
}

//修改操作
@Test
public void update(){
//组织user对象
User user = new User();
user.setId(1L);
user.setAge(28);
//通过id更新该user对象
int updateById = userMapper.updateById(user);
System.out.println("updateById:" + updateById);//影响的行数
}

}

2、自动填充

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等;
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:

数据库表中添加自动填充字段:

在User表中添加datetime类型的新的字段 create_time、update_time;

数据库表中添加create_time和update_time两个字段:

【谷粒学院】002-Mybatis Plus:主键策略、实现自动填充、乐观锁_mybatis

【谷粒学院】002-Mybatis Plus:主键策略、实现自动填充、乐观锁_数据库_02

实体上添加注解:

package com.zibo.mybatisplus.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;

import java.util.Date;

@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
//创建时间
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}

创建类,实现MetaObjectHandler接口:

package com.zibo.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

//创建填充
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);//metaObject元数据
this.setFieldValByName("updateTime",new Date(),metaObject);//metaObject元数据
}

//更新填充
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);//metaObject元数据
}
}

添加一条数据:

//添加操作
@Test
public void add(){
//组织user对象
User user = new User();
user.setName("zb");
user.setAge(24);
user.setEmail("18838186892@163.com");
//添加到数据库
int insert = userMapper.insert(user);
System.out.println("insert:" + insert);//影响的行数
System.out.println(user);//id自动回填
}

神奇的事情发生了:

【谷粒学院】002-Mybatis Plus:主键策略、实现自动填充、乐观锁_乐观锁_03

注意:

自动填充不是必然的,创建时间和更新时间也可以像其他属性(例如姓名、年龄等一样直接set);

user.setCreateTime(new Date());
user.setUpdateTime(new Date());

三、乐观锁

1、什么是乐观锁

主要用来解决丢失更新的问题;

如果不考虑事务的隔离性,会产生读问题:

脏读、不可重复读、幻读;

写问题:丢失更新;

2、什么叫丢失更新

并发情况下,多个线程同时修改同一数据,之后提交的数据会把之前提交的数据覆盖;

解决方案:悲观锁(一般不用)、乐观锁;

悲观锁:一个线程操作数据的时候其他线程都不能操作(串行);

乐观锁:为要修该的数据设置一个版本号字段,改之前比较当前数据版本号与数据库中版本号是否一致,一致则进行修改,并将版本号+1;

3、使用Mybatis Plus实现乐观锁

主要适用场景:

当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新;

乐观锁实现方式:

取出记录时,获取当前version;

更新时,带上这个version;

执行更新时, set version = newVersion where version = oldVersion;

如果version不对,就更新失败;

步骤:

(1)在数据库中添加version字段:

ALTER TABLE `user` ADD COLUMN `version` INT

(2)在实体类添加version字段,并添加 @Version 注解

package com.zibo.mybatisplus.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

import java.util.Date;

@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
//创建时间
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
//版本号:用于乐观锁
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
}

(3)使用元对象处理器接口添加version的insert默认值

package com.zibo.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

//元对象处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

//创建填充
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);//metaObject元数据
this.setFieldValByName("updateTime",new Date(),metaObject);//metaObject元数据
//添加版本号
this.setFieldValByName("version", 1, metaObject);
}

//更新填充
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);//metaObject元数据
}
}

特别说明:

支持的数据类型只有 int、Integer、long、Long、Date、Timestamp、LocalDateTime;

整数类型下 newVersion = oldVersion + 1;

newVersion 会回写到 entity 中;

仅支持 updateById(id) 与 update(entity, wrapper) 方法;

在 update(entity, wrapper) 方法下,wrapper 不能复用;

(4)在 MybatisPlusConfig 中注册 Bean

创建config包——创建MybatisPlusConfig类

(此时可以删除主类中的 @MapperScan 扫描注解)

package com.zibo.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
@MapperScan("com.zibo.mybatisplus.mapper")
public class MybatisPlusConfig {
/*
* 乐观锁插件旧版本,已过时
*/
// @Bean
// public OptimisticLockerInterceptor optimisticLockerInterceptor() {
// return new OptimisticLockerInterceptor();
// }
/**
* 乐观锁插件新版本
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}

(5)测试乐观锁插件

先添加一条新数据,然后修改这条数据,看效果:

添加:

//添加操作
@Test
public void add(){
//组织user对象
User user = new User();
user.setName("zb002");
user.setAge(24);
user.setEmail("18838186892@163.com");
//添加到数据库
int insert = userMapper.insert(user);
System.out.println("insert:" + insert);//影响的行数
System.out.println(user);//id自动回填
}

修改:

/**
* 测试 乐观锁插件
*/
@Test
public void testOptimisticLocker() {
//查询
User user = userMapper.selectById(1332883585346080769L);
//修改数据
user.setName("zb002");
user.setEmail("zb002@qq.com");
//执行更新
userMapper.updateById(user);
}

结果:

【谷粒学院】002-Mybatis Plus:主键策略、实现自动填充、乐观锁_乐观锁_04

举报

相关推荐

0 条评论