Spring声明式事务@Transactional详解,事务隔离级别和传播⾏
为
@Transactional注解⽀持9个属性的设置,这⾥只讲解其中使⽤较多的三个属性:readOnly、propagation、isolation。其中propagation属性⽤来枚举事务的传播⾏为,isolation⽤来设置事务隔离级别,readOnly进⾏读写事务控制。
@Service
@Transactional(readOnly = true)
public class AppTradeRec2Service extends BaseService {
@Autowired
private AppTradeRecDao appTradeRecDao;
@Autowired
private ConsInfoDao consInfoDao;
@Transactional(readOnly = false)
public void payCharge(TradeRec tradeRec) {
User usr = User();
ConsInfo cons = Id());
//修改交易记录
tradeRec.AccountAmt());
tradeRec.AccountAmt() - RcvAmt());
tradeRec.setIsPay("99");
appTradeRecDao.save(tradeRec);
//修改账户余额
cons.AccountAmt() - RcvAmt());
consInfoDao.save(cons);
}
}
⼀、readOnly读写事务控制
readOnly=true表明所注解的⽅法或类只是读取数据。
readOnly=false表明所注解的⽅法或类是增加,删除,修改数据。
⼆、isolation事务隔离级别
我们在使⽤事务过程中,通常会发⽣以下三种情况:
1、脏读(dirty read):当⼀个事务读取另⼀个事务尚未提交的修改时,产⽣脏读。
2、不可重复读(non-repeatable read):同⼀查询在同⼀事务中多次进⾏,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发⽣⾮重复读。
3、幻像读(phantom read):同⼀查询在同⼀事务中多次进⾏,由于其他提交事务所做的插⼊操作,每次返回不同的结果集,此时发⽣幻像读。
针对上述三种情况,Spring提供了5种事务隔离级别予以解决:
1、DEFAULT默认级别
DEFAULT为数据源(数据库)的默认隔离级别,以⽬前常⽤的MySQL为例,默认的隔离级别通常为REPEATABLE_READ。
spring怎么读 变声2、READ_UNCOMMITTED未授权读取级别
这是最低的隔离级别,⼀个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读。
3、READ_COMMITTED授权读取级别
以操作同⼀⾏数据为前提,读事务允许其他读事务和写事务,未提交的写事务禁⽌其他读事务和写事务。此隔离级别可以防⽌更新丢失、脏读,但不能防⽌不可重复读、幻读。此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现。
4、REPEATABLE_READ可重复读取级别
保证同⼀事务中先后执⾏的多次查询将返回同⼀结果,不受其他事务影响。以操作同⼀⾏数据为前提,读事务禁⽌其他写事务,但允许其他读事务,未提交的写事务禁⽌其他读事务和写事务。此隔离级别可以防⽌更新丢失、脏读、不可重复读,但不能防⽌幻读。
5、SERIALIZABLE序列化级别
所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰。提供严格的事务隔离,此隔离级别可以防⽌更新丢失、脏读、不可重复读、幻读。如果仅仅通过“⾏级锁”是⽆法实现事务序列化的,必须通过其他机制保证新插⼊的数据不会被刚执⾏查询操作的事务访问到。
隔离级别越⾼,越能保证数据的完整性和⼀致性,但是对并发性能的影响也越⼤。对于多数应⽤程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免更新丢失、脏读,⽽且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应⽤程序采⽤悲观锁或乐观锁来控制。
三、Propagation事务传播⾏为
Propagation属性⽤来枚举事务的传播⾏为。所谓事务传播⾏为就是多个事务⽅法相互调⽤时,事务如何
在这些⽅法间传播。Spring⽀持7种事务传播⾏为,默认为REQUIRED。
1、REQUIRED
REQUIRED是常⽤的事务传播⾏为,如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。
2、SUPPORTS
SUPPORTS表⽰当前⽅法不需要事务上下⽂,但是如果存在当前事务的话,那么这个⽅法会在这个事务中运⾏。
3、MANDATORY
MANDATORY表⽰该⽅法必须在事务中运⾏,如果当前事务不存在,则会抛出⼀个异常。不会主动开启⼀个事务。
4、REQUIRES_NEW
REQUIRES_NEW表⽰当前⽅法必须运⾏在它⾃⼰的事务中。⼀个新的事务将被启动,如果存在当前事
务,在该⽅法执⾏期间,当前事务会被挂起(如果⼀个事务已经存在,则先将这个存在的事务挂起)。如果使⽤JTATransactionManager的话,则需要访问TransactionManager。
5、NOT_SUPPORTED
NOT_SUPPORTED表⽰该⽅法不应该运⾏在事务中,如果存在当前事务,在该⽅法运⾏期间,当前事务将被挂起。如果使⽤JTATransactionManager的话,则需要访问TransactionManager。
6、NEVER
NEVER表⽰当前⽅法不应该运⾏在事务上下⽂中,如果当前正有⼀个事务在运⾏,则会抛出异常。
7、NESTED
NESTED表⽰如果当前已经存在⼀个事务,那么该⽅法将会在嵌套事务中运⾏。嵌套的事务可以独⽴于当前事务进⾏单独地提交或回滚。如果当前事务不存在,那么其⾏为与REQUIRED⼀样。嵌套事务⼀个⾮常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。⽽内层事务操作失败并不会引起外层事务的回滚。
综上所述,NESTED和REQUIRES_NEW⾮常相似,都是开启⼀个属于它⾃⼰的新事务。使⽤REQUIR
ES_NEW时,内层事务与外层事务就像两个独⽴的事务⼀样,⼀旦内层事务进⾏了提交后,外层事务不能对其进⾏回滚。当内部事务开始执⾏时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执⾏。两个事务互不影响,两个事务不是⼀个真正的嵌套事务,同时它还需要JTA事务管理器的⽀持。
使⽤NESTED时,外层事务的回滚可以引起内层事务的回滚。⽽内层事务的异常并不会导致外层事务的回滚,它是⼀个真正的嵌套事务。嵌套事务开始执⾏时, 它将取得⼀个 savepoint,如果这个嵌套事务失败, 将回滚到此savepoint。潜套事务是外部事务的⼀部分, 只有外部事务结束后它才会被提交。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论