文章目录
- 一、逻辑删除实现
- 二、乐观锁实现
- 2.1 悲观锁和乐观锁场景和介绍
- 2.2 具体技术和方案:
- 2.3 版本号乐观锁技术的实现流程
- 2.4 使用mybatis-plus数据使用乐观锁
- 三、防全表更新和删除实现
- 三、代码生成器(MyBatisX插件)
一、逻辑删除实现
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
逻辑删除实现:
- 数据库 和 实体类 添加逻辑删除字段
- 数据表添加逻辑删除字段
- 可以是一个布尔类型、整数类型或枚举类型。
ALTER TABLE USER ADD deleted INT DEFAULT 0 ; # int 类型 1 逻辑删除 0 未逻辑删除
- 实体类添加逻辑删除属性
@Data
public class User {
private Long id;
@TableField(value = "nickname",exist = false)
private String name;
private Integer age;
private String email;
// 当前属性对应的列就是逻辑删除的状态字段
// 当删除数据时,自动变成修改此列的属性值 默认0未删除 1删除
// 查询时,默认只查询 deleted = 0 未删除的数据
@TableLogic
private Integer deleted;
}
- 指定逻辑删除字段和属性值
- 单一指定
- 在实体类属性上创建属性 指定注解
@TableLogic
- 在实体类属性上创建属性 指定注解
- 全局指定
- yml 配置文件 添加
logic-delete-field
源码中默认值 就设置了未删除0 删除为1,可以保持默认即可。
- yml 配置文件 添加
- 单一指定
- 测试:
- 逻辑删除:不使用delete语句而是修改语句 update user set deleted=1 where id=#{id}
- 物理删除:delete from user where id=#{id}
@Test
public void delete_test2(){
userMapper.deleteById(2);
}
Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
正常查询 : 默认查询非逻辑删除数据
二、乐观锁实现
2.1 悲观锁和乐观锁场景和介绍
需求前置:并发问题演示
使用乐观锁/悲观锁解决:
乐观锁和悲观锁是在并发编程中用于处理并发访问和资源竞争的两种不同的锁机制
- 悲观锁
- 当A在使用时,上锁了,B尝试使用被拒绝,因为上锁了
- 只能等A用完后,解锁了,B再次去尝试使用。
- 乐观锁
- 当A使用,不会上锁,B可以尝试使用,但被告知已被占用,不能用
- 区别于悲观锁 -> 乐观锁的B会反复的尝试,直到A使用完毕
- 这两者都是解决并发数据问题的思路,不是具体技术
2.2 具体技术和方案:
乐观锁:
- 版本号/时间戳:
- 为数据添加一个版本号或时间戳字段,每次更新数据时,
- 比较当前版本号或时间戳与期望值是否一致,
- 若一致则更新成功,否则表示数据已被修改,需要进行冲突处理。
- CAS(Compare-and-Swap)
- 无锁数据结构
- 无锁队列、无锁哈希表等…
悲观锁:
- 锁机制
- 互斥锁(Mutex Lock)或读写锁(Read-Write Lock)
- 数据库锁
- 数据库层面使用行级锁或表级锁来控制并发访问
- 信号量
2.3 版本号乐观锁技术的实现流程
- 每条数据添加一个版本号字段version
- 取出记录时,获取当前 version
- 更新时,检查获取版本号是不是数据库当前最新版本号
- 如果是[证明没有人修改数据], 执行更新, set 数据更新 , version = version+ 1
- 如果 version 不对[证明有人已经修改了],我们现在的其他记录就是失效数据!就更新失败
2.4 使用mybatis-plus数据使用乐观锁
- 添加版本号更新插件,在springboorMain类
/**
* 将 mybatis-plus 插件加入到IOC容器
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//mybatis-plus的插件集合【将需要的插件加入到这个集合中即可,比如分页插件,乐观锁插件等】
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//乐观锁【版本号插件】mybatis-plus 会在更新时,每次帮助我们对比版本号字段和增加版本号+1
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
- 数据库添加version字段
ALTER TABLE USER ADD VERSION INT DEFAULT 1 ; # int 类型 乐观锁字段
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 仅支持
updateById(id)
与update(entity, wrapper)
方法
- 实体类添加version属性
@Version
private Integer version;
- 测试 正常更新
//演示乐观锁生效场景
@Test
public void testQuick7(){
//步骤1: 先查询,在更新 获取version数据
//同时查询两条,但是version唯一,最后更新的失败
User user = userMapper.selectById(5);
User user1 = userMapper.selectById(5);
user.setAge(20);
user1.setAge(30);
userMapper.updateById(user);
//乐观锁生效,失败!
userMapper.updateById(user1);
}
先查再改:
三、防全表更新和删除实现
针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除
- 添加防止全表更新和删除拦截器
// 防止全表删除和更新拦截器
mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
三、代码生成器(MyBatisX插件)
使用mybatisX插件,自动生成sql语句实现
MyBatisX快速代码生成_官方文档