Java 如何防止 JPA 回滚事务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1701750/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to prevent JPA from rolling back transaction?
提问by D. Wroblewski
Methods invoked:
1. Struts Action
2. Service class method (annotated by @Transactional)
3. Xfire webservice call
调用的方法:
1. Struts Action
2. 服务类方法(@Transactional 注释)
3. Xfire webservice 调用
Everything including struts (DelegatingActionProxy) and transactions is configured with Spring.
包括 struts (DelegatingActionProxy) 和事务在内的一切都是用 Spring 配置的。
Persistence is done with JPA/Hibernate.
持久化是通过 JPA/Hibernate 完成的。
Sometimes the webservice will throw an unchecked exception. I catch this exception and throw a checked exception. I don't want the transaction to roll back since the web service exception changes the current state. I have annotated the method like this:
有时 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);
}
}
I still get this exception:
我仍然收到此异常:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
When I try to reproduce this with junit, the transaction isn't marked for roll back and it's still possible to commit the transaction.
当我尝试用 junit 重现这个时,事务没有标记为回滚,并且仍然可以提交事务。
How do I make Spring not to roll back the transaction?
如何让 Spring 不回滚事务?
采纳答案by D. Wroblewski
Managed to create a test case for this problem:
设法为此问题创建了一个测试用例:
@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);
}
}
WebService:
网络服务:
@Transactional(readOnly = true)
public class WebService {
public void letsThrowAnException() {
throw new XFireRuntimeException("test!");
}
}
This will recreate the rollback-exception.
这将重新创建回滚异常。
Then I realized that the transaction is probably being marked as rollbackOnly in WebService.letsThrowAnException since WebService is also transactional. I moved to annotation:
然后我意识到事务可能在 WebService.letsThrowAnException 中被标记为 rollbackOnly,因为 WebService 也是事务性的。我转到注释:
@Transactional(noRollbackFor={XFireRuntimeException.class})
public void letsThrowAnException() {
Now the transaction isn't being rolled back and I can commit the changes to Order.
现在事务没有被回滚,我可以提交对 Order 的更改。
回答by Aaron Digulla
You must not throw an exception where Spring can see it. In this case, you must not throw WebServiceOrderFailed()
. The solution is to split the code into two methods. The first method does the error handling and returns the exception, the outer method creates the transaction.
您不能在 Spring 可以看到的地方抛出异常。在这种情况下,您不能抛出WebServiceOrderFailed()
. 解决方案是将代码拆分为两种方法。第一个方法进行错误处理并返回异常,外部方法创建事务。
[EDIT] As for noRollbackFor
: Try to replace Exception.class
with WebServiceOrderFailed.class
.
[编辑] 至于noRollbackFor
:尝试替换Exception.class
为WebServiceOrderFailed.class
.