三连多大胆,就有多大产!开源促使进步,献给每一位技术使用者和爱好者! 干货满满,摆好姿势,准备发车
一、乐观锁
乐观锁是用来解决多线程情况下同一条数据同时可能被多人一起修改,造成数据紊乱的一种解决方案,当更新一条数据时,希望这条数据没有被别人更新,也就是说实现线程安全的数据更新。
判断有没有被修改的策略就是在准备更新时获取该数据的版本,在更新时检查版本是否相同,更新后将数据的版本修改来实现。
对于乐观锁和悲观锁的详细介绍可以参考 什么是乐观锁,什么是悲观锁 文章
1.1、实现方式
在Mybatis Plus步骤如下
- 取出记录时,获取当前version
- 更新记录时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
1.2、实现步骤
- 在数据表中新增
version 字段,类型为int - 在实体类中新增
version 属性,并使用 @Version 注解修饰 - 元数据处理接口添加 version 的
insert 默认值(可以不做,目的在于自动填充有个默认值而已) - 编写配置类,配置
乐观锁插件
1.3、数据库添加字段
基于 MyBatis-Plus【2】 也就是上篇文章的基础,在您自己的表中创建一个 version 字段,也可以按照下方sql实现:
ALTER TABLE `user` ADD COLUMN `version` INT
1.4、实体类
- @Version:实现乐观锁注解
- @TableField(fill = FieldFill.INSERT):实现自动填充,在新增数据时填充一个初始的版本号,当然您也可以设置数据库的默认值等方式
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
1.5、元数据处理接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
......
this.setFieldValByName("version",1,metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
......
}
}
1、支持的数据类型只有int、Integer、long、Long、Date、Timestamp、LocalDateTime 2、整数类型下 newVersion = oldVersion + 1 3、newVersion会写回到entity中 4、仅支持 updateById(id) 和 update(entity,warpper)方法 5、在update(entity,warpper)方法下,warpper不能重用
1.6、乐观锁配置类
@Configuration
@EnableTransactionManagement
@MapperScan(value = "com.buye.mp.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
1.7、测试
首先新增一条数据,因为有自动填充version,所以它的version是1,然后再根据id修改
@Test
public void addUser() {
User user = new User();
user.setName("不夜同学");
user.setEmail("test10.@baomidou.com");
user.setAge(14);
int row = userMapper.insert(user);
System.out.println("成功新增" + row + "条数据");
}
@Test
public void testOptimisticLokker() {
User user = userMapper.selectById(1452181379893747714L);
user.setAge(18);
userMapper.updateById(user);
}
效果图如下,默认version为1,修改后version为2
sql执行如下
二、逻辑删除
逻辑删除:假删除 ,将对应数据中代表是否删除字段状态修改为 被删除状态 ,之后数据仍然存在与数据库中;
物理删除:真实删除 :将对应数据从数据库中删除,之后查询不到此条被删除数据;
2.1、实现步骤
-
想数据库中添加 deleted 字段 -
实体类中添加 deleted 字段 -
元对象处理器接口添加 deleted 的 insert 默认值(可以不做,只是为了新增数据时有默认值) -
application.properties 加入配置 -
在配置类中配置Bean【mybatis plus高版本已经不需要配置了】
2.2、新增字段
ALTER TABLE `user` ADD COLUMN `deleted` boolean
2.3、实体类新增deleted字段
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
2.4、application配置文件
该配置可以不做,默认0未删除,1以删除
# 逻辑删除已删除值(默认为1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑删除未删除值(默认为0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
2.5、测试
2.5.1、新增数据
@Test
public void addUser() {
User user = new User();
user.setName("不夜学长");
user.setEmail("test11.@baomidou.com");
user.setAge(14);
int row = userMapper.insert(user);
System.out.println("成功新增" + row + "条数据");
}
新增数据的deleted默认值为0,这里我们并没有设置自动填充哦!
2.5.2、删除数据
@Test
public void testLogicDelete() {
int row = userMapper.deleteById(1452267209106739202L);
System.out.println(row);
}
测试结果
2.5.3、添加逻辑删除后的查询
配置逻辑删除下的查询自带上 deleted = 0 条件
2.6、注意
如果需要查询出被逻辑删除的数据,那么就需要自己写sql语句啦
只对自动注入的sql起效:
- 插入: 不作限制
- 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
- 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
- 删除: 转变为 更新
例如:
- 删除:
update user set deleted=1 where id = 1 and deleted=0 - 查找:
select id,name,deleted from user where deleted=0
字段类型支持说明:
- 支持所有数据类型(推荐使用
Integer ,Boolean ,LocalDateTime ) - 如果数据库字段使用
datetime ,逻辑未删除值和已删除值支持配置为字符串null ,另一个值支持配置为函数来获取值如now()
附录:
- 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
- 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示
好了,对于mybatis-plus的 逻辑删除 和 乐观锁 分享到这里,如果您的项目中使用到mybatis-plus,这两个功能一定要用上。
|