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 }