gpt4 book ai didi

java - 我把 noRollbackFor 放在哪里有关系吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:48:30 24 4
gpt4 key购买 nike

在 Spring ,如果我有:

ServiceA.serviceA() -> ServiceB.serviceB() -> ServiceC.serviceC() ->ServiceD.serviceD()

ServiceD.serviceD() 可以抛出运行时异常:MyRuntimeException,它会传播回 ServiceA.serviceA catch block 。我将 @Transactional(noRollbackFor=[MyRuntimeException.class]) 放在哪个服务上重要吗?

把它放在任何服务上有什么区别吗?

注意:我所有的服务都被标记为@Transactional

最佳答案

由于您没有给出精确的信息,我假设您使用的是 PROPAGATION_REQUIRED 的默认传播。在这种情况下,4 个服务将使用相同的事务,如果三个内部服务中的任何一个由于异常而将事务标记为只读,外部服务将收到 UnexpectedRollbackException 通知它请求的提交实际上导致了回滚。来自 Spring 引用手册:但是,在内部事务范围设置仅回滚标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务范围静默触发)是意外。此时会抛出相应的 UnexpectedRollbackException。这是预期的行为,因此事务的调用者永远不会被误导以为提交已执行,但实际上并未执行。因此,如果内部事务(外部调用者不知道)默默地将事务标记为仅回滚,则外部调用者仍会调用提交。外部调用者需要接收 UnexpectedRollbackException 以清楚地指示执行了回滚。。而如果外层事务因为异常决定回滚事务,则事务显然会被回滚。

因此,如果没有任何服务捕获异常,并且如果您使用 PROPAGATION_REQUIRED 的传播,至少四个涉及的方法必须使用 @Transactional(noRollbackFor=[MyRuntimeException .class]).

使用 noRollbackFor=[MyRuntimeException.class] 的替代方法是在 ServiceD 的适当方法中捕获异常。在那种情况下,异常将永远不会爬上堆栈,并且任何事务代理都不会知道它发生了。提交通常会在事务结束时发生。

根据评论编辑:

如果您想进一步控制异常管理,您可以尝试复制方法:一种事务性方法,它在您的服务类中调用非事务性方法。如果您不想在链中使用另一个事务代理,则可以调用非事务代理。但这只有在这个用例(一个服务类调用另一个具有特殊异常要求的服务类)异常时才有意义。

作为替代方案,您可以在其他服务类上注入(inject)实现,而不是注入(inject)事务代理 (@Autowired private ServiceBImpl serviceB;)。由于您已经在外层获得了一个事务,因此所有 DAO 操作都应该没问题,并且由于在外层只有一个事务代理,您有一个用于异常管理的单一控制点。注入(inject)类而不是接口(interface)是相当不常见的,您应该用红色闪烁字体记录原因 :-),但它应该满足您的要求。

关于java - 我把 noRollbackFor 放在哪里有关系吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25489547/

24 4 0