【问题标题】:How to prevent JPA from rolling back transaction?如何防止 JPA 回滚事务?
【发布时间】:2010-12-14 16:15:33
【问题描述】:

调用的方法:
1. Struts 动作
2.服务类方法(@Transactional注解)
3. Xfire webservice调用

包括 struts (DelegatingActionProxy) 和事务在内的一切都是用 Spring 配置的。

持久性是通过 JPA/Hibernate 完成的。

有时网络服务会抛出未经检查的异常。我捕获了这个异常并抛出了一个检查异常。我不希望事务回滚,因为 Web 服务异常更改了当前状态。我已经对方法进行了这样的注释:

@Transactional(noRollbackFor={XFireRuntimeException.class, Exception.class})
public ActionForward callWS(Order order, ....) throws Exception
  (...)
  OrderResult orderResult = null;

  try {
    orderResult = webService.order(product, user)
  } catch (XFireRuntimeException xfireRuntimeException) {
    order.setFailed(true);
    throw new WebServiceOrderFailed(order);
  } finally {
    persist(order);
  }
}

我仍然得到这个异常:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

当我尝试使用 junit 重现此问题时,该事务未标记为回滚,并且仍然可以提交该事务。

如何让 Spring 不回滚事务?

【问题讨论】:

    标签: java hibernate spring jpa struts


    【解决方案1】:

    你不能在 Spring 可以看到的地方抛出异常。在这种情况下,您不能抛出WebServiceOrderFailed()。解决方案是将代码拆分为两种方法。第一个方法进行错误处理并返回异常,外部方法创建事务。

    [编辑] 至于noRollbackFor:尝试将Exception.class 替换为WebServiceOrderFailed.class

    【讨论】:

    • 这是不正确的。 noRollbackFor 检查指定的异常类及其所有子类:static.springsource.org/spring/docs/2.5.x/api/org/… 此外,默认情况下检查的异常不会触发回滚:static.springsource.org/spring/docs/2.5.x/reference/…
    • 这并不能解释为什么上面的代码会在 WebServiceOrderFailed 上回滚。
    • 我的猜测是 WebServiceOrderFailed 是一个 RuntimeException 并且上面的代码 (noRollbackFor={..., Exception.class}) 不能有任何效果,因为 Exception 是专门处理的(否则,继承代码也会忽略 RuntimeException,因为它扩展了 Exception )。
    • 感谢您的意见。你们为我指明了正确的方向! (WebServiceOrderFailed 扩展了异常,这是一个检查异常)
    • 请帮助我遇到同样的问题stackoverflow.com/questions/54343137/…
    【解决方案2】:

    设法为这个问题创建了一个测试用例:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"file:web/WEB-INF/spring/applicationContext.xml",
            "file:web/WEB-INF/spring/services.xml"})
    @Transactional
    public class DoNotRollBackTest {
        @Autowired FakeService fakeService;
    
        @Test
        @Rollback(false)
        public void testRunXFireException() {
            fakeService.doSomeTransactionalStuff();
        }
    }
    

    假服务:

    @Service
    public class FakeService {
        @Autowired private EcomService ecomService;
        @Autowired private WebService webService;
    
        @Transactional(noRollbackFor={XFireRuntimeException.class})
        public void doSomeTransactionalStuff() {
            Order order = ecomService.findOrderById(459);
    
            try {
                webService.letsThrowAnException();
            } catch (XFireRuntimeException e) {
                System.err.println("Caugh XFireRuntimeException:" + e.getMessage());
            }
    
            order.setBookingType(BookingType.CAR_BOOKING);
            ecomService.persist(order);
        }
    }
    

    网络服务:

    @Transactional(readOnly = true)
    public class WebService {
        public void letsThrowAnException() {
            throw new XFireRuntimeException("test!");
        }
    }
    

    这将重新创建回滚异常。

    然后我意识到事务可能在 WebService.letsThrowAnException 中被标记为 rollbackOnly,因为 WebService 也是事务性的。我移到注释:

    @Transactional(noRollbackFor={XFireRuntimeException.class})
        public void letsThrowAnException() {
    

    现在事务没有回滚,我可以将更改提交给 Order。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-17
      • 2014-11-29
      • 1970-01-01
      • 2017-06-13
      • 2015-10-25
      • 2013-03-27
      • 2015-05-31
      • 2012-02-04
      相关资源
      最近更新 更多