Spring @Transactional注解和ReentrantLock同步锁同时使用不能同步的问题

结论:果在service层的方法上同时使用事务和同步锁无法保证数据同步。

 1 @Service
 2 public class ServiceImpl{
 3         
 4     private static Lock lock = new ReentrantLock(false);
 5         
 6     @Transactional(rollbackFor = Exception.class)
 7     public void update() {
 8         try {
 9             lock.lock();
10             ... ...
11         } catch (Exception e) {
12             e.printStackTrace();
13         } finally {
14             lock.unlock();
15         }
16     }
17 }

上面这个例子无法保证数据的一致性,synchronized 同理。

原因:

  根据spring的AOP的特性,会在update方法之前开启事务,之后再加锁,当锁住的代码执行完成后,再提交事务。

  由于lock代码块执行是在事务之内执行的,在代码块执行完时,事务还未提交,因此其它线程进入synchronized代码块后,读取的数据库数据不是最新的(脏读)。

解决方案:

  1.在还没有开启事务之前就加同步锁,用加锁的方法调用加事务的方法

 1 @Service
 2 public class ServiceImpl{
 3 
 4     private static Lock lock = new ReentrantLock(false);
 5 
 6     public void update1() {
 7         try {
 8             lock.lock();
 9             update2();
10         } catch (Exception e) {
11             e.printStackTrace();
12         } finally {
13             lock.unlock();
14         }
15     }
16 
17     @Transactional(rollbackFor = Exception.class)
18     public void uodate2() {
19         ... ...
20     }
21 }

  2.把锁放到上一层

 1 @Controller
 2 public class TestController{
 3     @Autowired
 4     private IServiceImpl serviceImpl;
 5         
 6     private static Lock lock = new ReentrantLock(false);
 7         
 8     public String test() {
 9         try {
10             lock.lock();
11             serviceImpl.update();
12         } catch (Exception e) {
13             e.printStackTrace();
14         } finally {
15             lock.unlock();
16         }
17     }
18 }
19 
20 @Service
21 public class ServiceImpl{
22 
23     @Transactional(rollbackFor = Exception.class)
24     public void update() {
25         ... ...
26     }
27 }

 

posted @ 2019-10-30 16:50  猿了个码  阅读(2428)  评论(0编辑  收藏  举报