项目场景:
在导入数据时,由于重复点击上传导致插入的数据重复。
问题描述
@Transactional(rollbackFor = Exception.class)
public synchronized Integer batchImportProvisions(List<ImportLegalProvisionsDTO> list, Long legalId) {
}
原因分析:
- 当使用synchronized锁时,如果方法上加了开启事务的注解比如: @Transactional时,因为spring的事务的通过aop实现的,那么就会在执行这个方法之前开启一个事务,在方法执行之后提交事务。
- 而synchronized锁是方法上加锁,所以是在开启事务之后才上锁,数据库默认的事务级别是RR级别(可重复读),多个事务之间是相互不影响的,每个事务查询都是当前数据库数据的一个快照视图。
- 如果两个请求同时过来,就同事开启了两个事务比如:A,B。这会有两种情况,
- 第一种可能A释放锁以后,B进入了方法由于A还没有提交,B也就查询不到A插入的数据。
- 第二种A释放了锁还没提交事务时,B进入了方法并且进行了一次条件查询,此时就会生成一个快照视图,就算A提交了事务,B再次进行查询也不会查询到A插入后的数据,因为数据库默认是RR隔离级别。
解决方案:
在开启事务之前上锁就可以了,就是在调取事务方法之前使用synchronized关键字