调用的方法: 1. Struts Action 2.服务类方法(由@Transactional注释) 3. Xfire Web服务调用
包括struts(DelegatingActionProxy)和事务在内的所有内容都使用Spring进行配置。
持久性是通过JPA / Hibernate完成的。
有时,Web服务将引发未经检查的异常。我捕获了此异常并抛出了一个已检查的异常。我不希望事务回滚,因为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不回滚事务?
设法为这个问题创建了一个测试用例:
@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!"); } }
这将重新创建回滚异常。
然后我意识到该事务可能在WebService.letsThrowAnException中被标记为rollbackOnly,因为WebService也是事务性的。我移至注释:
@Transactional(noRollbackFor={XFireRuntimeException.class}) public void letsThrowAnException() {
现在,交易没有被回滚,我可以将更改提交到Order。