日期:2014-05-16  浏览次数:20364 次

事务传播性和隔离级别小记
1.项目中一些业务方法中可能涉及多个异步方法调用,某些异步方法可能调用失败,但之前的异步方法是不会回滚的,因此我本地需要每执行完一步异步调用就更新本地的状态,用于记录方法执行到哪里了。如果方法执行中失败过,则下次重新调用该方法时,我可以根据本地的状态判断不再执行之前已经调用过的异步方法。为了使更新状态的方法不会随方法调用失败而回滚,因此使用一个独立的事务,在spring的声明式事务中将事务传播性配置为Propagation.REQUIRES_NEW即可以满足要求,但有一点需要注意到是这个更新状态的方法需要放置到另外一个类里,究其原因还需进一步研究下。

2.另一个业务方法里首先需要调用方法A更新一些业务数据,如果后续方法有异常是需要回滚方法A的,后面还有一个方法B中会做类似上面所说记录过程状态的操作,这些方法里的更新操作是独立事务的。从业务上讲这些似乎都是合情合理的,但由于前后的操作都处理的是一张数据库表,这导致了一个很严重的问题——死锁。起先以为在事务隔离级别上设置为Isolation.READ_UNCOMMITTED可以解决,后来意识到事务的4个隔离级别只是对于数据可以见性的设置,而我的问题出在两次update操作上。方法A在第一个的事务中更新了表中某一条数据但还未提交,spring默认的事务隔离级别为Isolation.READ_COMMITTED,这是锁当前操作的数据行的。数据库中对该行数据加了排他锁,直到事务结束才会释放锁。而此时方法B在另一个事务中对同一张表的同一条数据进行update操作,方法B在等待方法A释放锁,方法A又要等待方法B调用结束,因而造成了死锁。最终解决的办法是方法A也做独立事务处理,其他相关的业务逻辑再做调整吧。