如何防止JPA回滚交易?

调用的方法:
1. Struts Action
2.服务类方法(由@Transactional注释)
3. Xfire webservice调用

包括struts(DelegatingActionProxy)和事务在内的所有东西都是用Spring配置的。

使用JPA / Hibernate完成持久化。

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

@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不回滚事务?

管理以创建此问题的测试用例:

 @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(); } } 

FakeService:

 @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!"); } } 

这将重新创建回滚exception。

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

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

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

你不能抛出Spring可以看到的exception。 在这种情况下,您不能抛出WebServiceOrderFailed() 。 解决方案是将代码分成两种方法。 第一种方法执行error handling并返回exception,外部方法创建事务。

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