乐观锁处理讲解
1、 概念:
乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么都不会上锁!如果出现了问题,再次更新值测试!
悲观锁:顾名思义十分悲观,它总是认为会出现问题,不论干什么都上锁,再操作!
2、 乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时 set newVersion = oldVersion where version = oldVersion
如果version不对,就更新失败
3、 测试MyBatis-Plus插件乐观锁
3.1、表中增加version字段
说明:类型为int,默认值为1
3.2、更新实体类
package com.will.pojo;
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(type = IdType.INPUT)
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 //乐观锁注解
private Integer version;
}
3.3、注册乐观锁组件
package com.will.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement //开启事务管理
@Configuration //配置类
public class AppMyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3.4、编写测试类(成功案例),注意观察生成的更新语句
@Test
void testOptimisticLocker() {
// 1.查询用户信息
User user = userMapper.selectById(11L);
// 2.修改用户信息
user.setName("张三");
user.setAge(18);
// 3.更新用户信息
userMapper.updateById(user);
}
3.5、编写测试类(失败案例),注意观察生成的语句
@Test
void testOptimisticLockerFail() {
// 线程1
User user = userMapper.selectById(11L);
user.setName("张三");
user.setAge(18);
// 模拟线程2执行了插队操作
User user2 = userMapper.selectById(11L);
user2.setName("李四");
user2.setAge(20);
userMapper.updateById(user2);
// 线程1更新
userMapper.updateById(user); //如果没有乐观锁,就会覆盖插队线程的值
}
查询操作
1、单条数据测试
@Test
void testSelectById() {
User user = userMapper.selectById(11L);
System.out.println(user);
}
2、测试批量查询
@Test
void testSelectBatchById() {
List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4, 5));
userList.forEach(System.out::println);
}
3、按条件查询
@Test
void testSelectByCondition() {
//自定义查询条件
HashMap<String, Object> map = new HashMap<>();
map.put("name", "李四");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询
1、配置拦截器组件
// 最新版
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
说明:添加至 AppMyBatisPlusConfig.java
2、直接使用Page对象
@Test
void testPage() {
// 参数一:当前页
// 参数二:每页条数
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
}
3、查看分页结果
删除操作
1、 根据ID删除记录
@Test
void testDeleteById() {
int result = userMapper.deleteById(11L);
System.out.println(result);
}
2、 批量删除
@Test
void testDeleteBatchByIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
System.out.println(result);
}
3、 根据条件删除
@Test
void testDeleteByCondition() {
//条件
HashMap<String, Object> map = new HashMap<>();
map.put("name", "李四");
int result = userMapper.deleteByMap(map);
System.out.println(result);
}
逻辑删除
1、 概念
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过变量来让该条数据失效
2、 数据库增加字段deleted,类型int,默认值0
3、 更新实体类,添加属性deleted
@TableLogic // 逻辑删除
private Integer deleted;
4、注册逻辑删除组件
// 注册逻辑删除组件
@Bean
public ISqlInjector qlInjector() {
return new LogicSqlInjector();
}
5、配置application.properties文件
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
6、测试删除
@Test
void testDeleteById() {
int result = userMapper.deleteById(10L);
System.out.println(result);
}
7、观察结果及生成的语句
说明:走的是更新操作,不是删除操作
8、测试查询
@Test
void testSelectById() {
User user = userMapper.selectById(10L);
System.out.println(user);
}
9、观察结果及生成的语句
说明:查询时会自动过滤逻辑删除数据