1、不要在事务里面加锁,这样当线程1 执行完操作,进行释放锁的时候,事务并没有提交。
其他线程就能获取锁,去并发的操作数据库。
2、如果一个声明式事务@Transactional注解中,包括了对多个表操作外,还包括了比如消息的传递,文件记录等操作,它们本身是不支持事务的,这个时候可以考虑编程式事务,自己控制事务的粒度。将对多个表的操作进行事务圈起来。
PS:消息的不可靠性可能会影响本地事务提交,所以也要把消息的发送放到事务外面。
我们这里记录了一个偏移量,发生并发问题,是因为前端发过来的多次请求,并没有保证请求之间有先后顺序,那么如果我线程A先来【想要将值更改为2】,拿分布式锁之前,突然sleep了,这个时候线程B并发的过来【想要将值更改为3】,拿到了分布式锁,改成了3,然后释放,然后线程A醒过来了,去拿锁,改成了2,最终数据库的值为2,相当于是个老值。
解决方案:
1.在读偏移量的值的时候就开始拿锁,这样的话会大大降低性能。
2.在拿到锁的时候,try代码块里面先进行双重校验。
总结:
写依赖于读【类似秒杀场景】的时候,要么乐观:CAS式校验是否已经被写过;
要么悲观:更大范围/粗粒度的锁