记:自旋乐观锁 + @Transactional注解导致读取数据一直不变的问题

场景
	在预约时,每个时间段限制预约人数位30人,新增、取消预约都会修改余量数据,
且后台也可以取消预约,虽然并发量不会有多高,但还是假装有点并发量,就思考了
一些方案。
思考可采取方案
1、synchronized
		如果是只有一个接口修改,那么用这个也行,直接来请求就排队,简单暴力;
		但是这里有多个接口都会修改,所以也没用

2、Redis
		把余量放入Redis中,通过incr/decr来增减;
		问题
			1)场景问题:该数据几乎每天都会生成,而且我们是代小程序开发,
			   如果商家入驻多了,数据也就多了,每个时间段的余量都存里面
			   不太现实
			2)因为新增如果出现问题,使用的是Redis,虽然可以通过切面为其
			   手动回滚,但也是比较麻烦

3、乐观锁
		1)Mybatis原生自己写乐观锁
		2)Mybatis Plus自带乐观锁

	综上考虑,最终采用了Mybatis Plus乐观锁,因为我们用的就是这个,其他的
是在想除了这个有什么其他方式来实现并发,下面是一个测试的Demo。
demo测试
  • 此处略去Spring Boot 整合 Mybatis Plus且配置乐观锁插件
  • 实体类
public class Test implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    private Integer num;

    private LocalDateTime updateTime;

    @Version
    private Integer version;
}
    • 解析

Mybatis Plus乐观锁

1、Mybatis Plus乐观锁支持格式:int,Integer,long,Long,Date,Timestamp,LocalDateTime
2、此处选择的Integer作为类型,因为用时间戳,有可能两个请求在同一秒
修改DB,这样也会造成覆盖,所以最终选择数字类型作为版本号
  • service
@Transactional(isolation = Isolation.SERIALIZABLE)
public void test() {
    while (true) {
        Test test = getById(2);
        test.setNum(test.getNum() + 1);
        boolean result = updateById(test);
        if (result) break;
    }
}
    • 解析
@Transactional作用
	1、为方法添加事务
	2、可指定隔离级别避免出现脏读、幻读、不可重复读
	3、可指定传播机制
	4、指定是否可读等
	
此处核心:一定要指定隔离级别,且为Isolation.READ_COMMITTED,原因如下
	1、READ_UNCOMMITTED会出现脏读,所以肯定不能选
	2、不填 == REPEATABLE_READ可以避免脏读和不可重复读,但是因为乐观锁,
肯定会修改失败,失败后会继续读取新数据,来再次修改,而如果此时隔离级别为
REPEATABLE_READ,那么会导致读取数据不会变化,因此不能选这个
	3、SERIALIZABLE:这个相当于排队操作,不存在脏乱差,但性能低,不考虑

READ_COMMITTED:
	该隔离级别只能防止脏读,允许出现幻读和不可重复读,而在乐观锁CAS时,
肯定需要重复读取数据,所以乐观锁的事务隔离级别需要指定为此

Github Demo

小结
	其实一开始一直在想,为什么不加@Transactional就可以读到新数据,加了
就不行,还想过Mybatis缓存的问题,但是禁用后结果还是一样,后面还考虑是不是
MySQL的问题,结果试了几个隔离级别,还真发现了问题,虽然知道脏、幻、不可重
复读和集中隔离级别能干吗,但是不理解,这次过后,才算理解了一些,也算解决了
自己长时间的一个困扰,学东西还是需要思考如何用,之前大多都是看,但不去思考
怎么用,也不去理解,果然,理解万岁- -
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值