【问题标题】:@Transactional (noRollbackFor=RuntimeException.class) does not prevent rollback on RuntimeException@Transactional (noRollbackFor=RuntimeException.class) 不会阻止 RuntimeException 上的回滚
【发布时间】:2015-03-07 03:34:05
【问题描述】:
@Transactional (noRollbackFor=RuntimeException.class)
public void methodA (Entity e){
   service.methodB(e);
}

---下面的服务方法---

@Transactional (propagation=Propagation.REQUIRES_NEW, noRollbackFor=RuntimeException.class)
public void methodB (Entity e){
   dao.insert(e);
}

methodB() 中的dao.insert(e) 导致主键冲突并引发ConstraintViolationExceptionRuntimeException 的子类)时,由于我使用了noRollbackFor 属性,我预计事务仍将提交。但我观察到外部事务(在methodA 上)仍然被HibernateTransactionManager 回滚并显示消息

org.springframework.transaction.UnexpectedRollback 异常: 事务回滚,因为它已被标记为仅回滚

我发现报告了类似的问题,但不完全是这个。

【问题讨论】:

  • 您是否将 globalRollbackOnParticipationFailure 设置为 false 例如<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="globalRollbackOnParticipationFailure" value="false" /> <property name="sessionFactory" ref="sessionFactory" /> </bean>
  • 很确定 sol4me 是在正确的轨道上 - 请参阅 stackoverflow.com/a/11205537/1594449
  • 听起来是个好主意,但我并不热衷于更改 globalRollbackOnParticipationFailure 的设置,因为我正在增强已经使用相同事务管理器的现有单片代码,我想保留现有代码不受我的更改影响 - 通过更改 tx 管理器配置似乎不可行。我可以做一些完全针对我的改变的事情吗?
  • 仅供参考,我还尝试在dao.insert(e); 中捕获RuntimeException 中的methodB 并在将其包装在检查异常中后将其重新抛出。我更改了noRollbackFor 以匹配使用的检查异常。然而,这并没有什么不同——methodA 中的外部事务仍然被回滚!
  • @ankur-singhal - 因为 methodB 正在开始一个新事务,所以谁为 methodA 启动事务有关系吗?

标签: java spring hibernate jpa transactions


【解决方案1】:

一旦捕获到异常,Hibernate Session 应该被丢弃并且事务应该回滚:

如果Session抛出异常,事务必须滚动 返回并丢弃会话。 Session的内部状态 异常发生后可能与数据库不一致。

因此,noRollbackFor 适用于可能引发异常的服务和 DAO 层。假设您有一个 gatewayService,它通过 Hibernate DAO 写入数据库并通过 emailService 发送电子邮件。如果 emailService 抛出 SendMailFailureException,您可以指示 gatewayService 在捕获此异常时不要回滚:

@Transactional(noRollbackFor=SendMailFailureException.class)
public void saveAndSend(Entity e){
   dao.save(e);
   emailService.send(new Email(e));
}

【讨论】:

  • 用一个例子很好地解释
  • @AndyDufresne 我的理解是——Method B有自己的事务,方法A事务会被挂起,所以作为proxy,proxy叫它target method method B,如果有异常发生在哪个@987654327配置了@,只处理这个事务,然后恢复method A的事务
  • 即使因为 Propagation.REQUIRES_NEW 有新事务,同样的原则也适用于 Hibernate Session。
  • @VladMihalcea 所以noRollBackFor 仅适用于不是数据库\休眠特定的异常?所以说DataIntegrityViolationException无论如何都会回滚?另外据我所知,即使拥有Propagation.REQUIRES_NEW 也无济于事,因为休眠会将链中的所有暂停事务标记为仅回滚,因为休眠将整个会话标记为回滚?
  • 没错。您可以在缓存不可用时使用它,但您仍然可以为来自数据库的请求提供服务。
猜你喜欢
  • 2016-05-03
  • 2021-10-30
  • 1970-01-01
  • 2017-07-22
  • 2013-09-16
  • 2016-03-04
  • 2019-01-27
  • 1970-01-01
相关资源
最近更新 更多