如何防止JPA事务回滚?

发布于 2024-08-10 08:03:43 字数 1012 浏览 5 评论 0原文

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

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

Methods invoked:
1. Struts Action
2. Service class method (annotated by @Transactional)
3. Xfire webservice call

Everything including struts (DelegatingActionProxy) and transactions is configured with Spring.

Persistence is done with 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:

@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.

How do I make Spring not to roll back the transaction?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

雪落纷纷 2024-08-17 08:03:43

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

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

这将重新创建回滚异常。

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

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

现在事务不会回滚,我可以将更改提交到订单。

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:

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

Now the transaction isn't being rolled back and I can commit the changes to Order.

好久不见√ 2024-08-17 08:03:43

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

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

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.

[EDIT] As for noRollbackFor: Try to replace Exception.class with WebServiceOrderFailed.class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文