Spring+Hibernate延迟和声明式事务处理最终解决方案

本文深入探讨了Spring中的事务传播行为,特别是PROPAGATION_NESTED和PROPAGATION_REQUIRED的区别和应用。阐述了嵌套事务的概念,如SavePoint,并指出在涉及外部系统交互时,如何选择合适的事务配置以避免数据不一致问题。同时提到了PROPAGATION_REQUIRED_NEW在确保独立事务操作中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring事务的正确配置可以给整个项目带来清晰的感觉,相反则是不稳定的因数。
  首先我们应该弄清楚Spring事务的属性问题,事务属性通常由事务的传播行为,事务的隔离级别,事务的超时值和事务只读标志组成,在项目的架构阶段,这些应该都会被关注,但在项目的开发过程中,由于多变的业务需求,事务的传播行为往往不被程序员关注,从而因忽略事务控制而导致的脏数据和不稳定。
  传播行为是事务应用于方法的边界,它定义了事务的建立,暂停等行为属性。
  在Spring中共有7种,它们分别是:

  *PROPAGATION_MANDATORY:规定了方法必须在事务中运行,否则会抛出异常;
  *PROPAGATION_NESTED:使方法运行在嵌套事务中,否则这个属性和PROPAGATION_REQUIRED属性的义相同;
  *PROPAGATION_NEVER:使当前方法永远不在事务中运行,否则抛出异常;
  *PROPAGATION_NOT_SUPPORTED:定义为当前事务不支持的方法,在该方法运行期间正在运行的事务会被暂停;
  *PROPAGATION_REQUIRED:规定当前的方法必须在事务中,如果没有事务就创建一个新事务,一个新事务和方法一同开始,随着方法的返回或抛出异常而终止;
  *PROPAGATION_REQUIRED_NEW:当前方法必须创建新的事务来运行,如果现存的事务正在运行就暂停它;
  *PROPAGATION_SUPPORTS:规定当前方法支持当前事务处理,但如果没有事务在运行就使用非事务方法执行;

在上述的传播行为中,值得我们关注的是:PROPAGATION_NESTED,PROPAGATION_REQUIRED,PROPAGATION_REQUIRED_NEW这三个。

  其中PROPAGATION_NESTED比PROPAGATION_REQUIRED多了一个嵌套事务的概念。在嵌套事务中又含有一个非常重要的概念,那就是“SavePoint”,我们可以认为是状态暂存点。但是在现实开发过程中,有很多这样误解这两种传播行为:如果一个服务配置成PROPAGATION_REQUIRED,而在这个服务里调用了另一个也需要事务控制的服务,那么另一个服务必须配置成PROPAGATION_NESTED。其实PROPAGATION_NESTED和PROPAGATION_REQUIRED两种行为在配置并没有强制的关联。PROPAGATION_REQUIRED就是说如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务,就新建一个事务;而PROPAGATION_NESTED用Juergen Hoeller的话来说就是“PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.

Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction. ”,也就是说 PROPAGATION_NESTED 开始一个 "嵌套的" 事务,  它是已经存在事务的一个子事务. 嵌套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

  经过上述的分析,显然在一些需要和外部系统打交道的项目中,不应该将所有的服务都配置成PROPAGATION_REQUIRED(默认就是这种传播行为),因为你很有可能在一个事务中通过WebService(暂且认为是这个)调用了外围系统,如果外围系统commit,而自身系统,由于Exception而rollback了,那么当本地系统再次访问外围系统时,数据的状态已经不是我们预想的那样的了,由于想到用log表来记录访问,程序员没有想到由于本地Exception导致log也没有记录下来。这样想来,对于log这种,其实应该设置传播行为为PROPAGATION_REQUIRED_NEW。

  那什么又是:PROPAGATION_REQUIRED_NEW呢?PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值