在我放置noRollbackFor的地方有用吗?

Mor*_*ive 8 java spring spring-transactions

在春天,如果我有:

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

哪里ServiceD.serviceD()可以抛出运行时异常:MyRuntimeException,它被传播回ServiceA.serviceAcatch块.我穿上哪种服务是否重要@Transactional(noRollbackFor=[MyRuntimeException.class])

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

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

Ser*_*sta 7

由于你没有给出精确度,我假设你使用的是默认传播PROPAGATION_REQUIRED.在该上下文中,4个服务将使用相同的事务,并且如果三个内部中的任何一个将事务标记为由于异常而为只读,则外部将获得UnexpectedRollbackException 通知它所请求的提交实际上导致了回滚.从Spring参考手册:但是,在内部事务作用域设置仅回滚标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务作用域静默触发)是意外的.此时抛出相应的UnexpectedRollbackException.这是预期的行为,因此事务的调用者永远不会被误导,假设在实际上没有执行提交.因此,如果内部事务(外部调用者不知道)以静默方式将事务标记为仅回滚,则外部调用者仍会调用commit.外部调用者需要接收UnexpectedRollbackException以清楚地指示已执行回滚..如果外部事务决定因异常而回滚事务,那么事务显然将被回滚.

因此,如果没有任何服务捕获异常,并且如果使用传播PROPAGATION_REQUIRED,则至少必须使用四个相关方法进行注释@Transactional(noRollbackFor=[MyRuntimeException.class]).

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

根据评论编辑:

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

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