无法提交JPA事务:标记为rollbackOnly的事务

编程入门 行业动态 更新时间:2024-10-27 16:33:57
本文介绍了无法提交JPA事务:标记为rollbackOnly的事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我在使用Spring和Hibernate的一个应用程序中工作,并且处理事务时遇到了问题。我得到了一个服务类,它从数据库中加载一些实体,修改它们的一些值,然后(当一切都有效时)将这些更改提交给数据库。如果新值无效(我只能在设置它们后才能检查),我不想坚持更改。为了防止Spring / Hibernate保存更改,我在该方法中抛出异常。但是,这会导致以下错误:

无法提交JPA事务:标记为rollbackOnly的事务 这是服务: pre $ @Service class MyService { @Transactional(rollbackFor = MyCustomException.class)$ b $ public void doSth()throws MyCustomException { //从数据库加载实体 //修改它们的一些值 //检查它们是否有效 if(invalid){//如果它们不是有效的,抛出异常 throw new MyCustomException(); } } }

是我如何调用它:

class ServiceUser { @Autowired private MyService myService; public void method(){ try { myService.doSth(); } catch(MyCustomException e){ // ... } } }

我希望发生的事情:没有对数据库进行更改,也没有任何用户可见的异常。

发生了什么:数据库没有更改,但应用程序崩溃:

org.springframework.transaction.TransactionSystemException:无法提交JPA交易; 嵌套异常是javax.persistence.RollbackException:标记为rollbackOnly的事务

正确设置事务到rollbackOnly,但为什么回滚与异常崩溃?

解决方案

我的猜测是 ServiceUser。 method()本身是事务性的。它不应该。这是为什么的原因。

以下是调用 ServiceUser.method()方法时会发生的情况: $ b

  • 事务拦截器拦截方法调用,并启动事务,因为没有事务处于活动状态。
  • 该方法称为
  • 该方法调用MyService.doSth()
  • 事务拦截器拦截方法调用,发现事务已经存在活动,并且不执行任何操作
  • 执行doSth()并引发异常事件拦截器拦截异常,将事务标记为rollbackOnly,并传播异常
  • ServiceUser.method()捕获异常并返回事务拦截器
  • ,因为它已启动事务,尝试承诺它。但是Hibernate拒绝这样做,因为事务被标记为rollbackOnly,所以Hibernate会抛出一个异常。事务拦截器通过抛出一个包装hibernate异常的异常来向调用者发出信号。
  • 现在如果 ServiceUser。 method()不是事务性的,这是发生了什么:

  • 该方法称为
  • 方法调用MyService.doSth()
  • 事务拦截器拦截方法调用,发现没有事务处于活动状态,从而启动事务
  • $执行b $ b
  • doSth()并引发异常
  • 事务拦截器拦截异常。由于它已经启动了事务,并且由于抛出异常,它将回滚事务并传播异常。
  • ServiceUser.method()捕获异常并返回
  • I'm using Spring and Hibernate in one of the applications that I'm working on and I've got a problem with handling of transactions.

    I've got a service class that loads some entities from the database, modifies some of their values and then (when everything is valid) commits these changes to the database. If the new values are invalid (which I can only check after setting them) I do not want to persist the changes. To prevent Spring/Hibernate from saving the changes I throw an exception in the method. This however results in the following error:

    Could not commit JPA transaction: Transaction marked as rollbackOnly

    And this is the service:

    @Service class MyService { @Transactional(rollbackFor = MyCustomException.class) public void doSth() throws MyCustomException { //load entities from database //modify some of their values //check if they are valid if(invalid) { //if they arent valid, throw an exception throw new MyCustomException(); } } }

    And this is how I invoke it:

    class ServiceUser { @Autowired private MyService myService; public void method() { try { myService.doSth(); } catch (MyCustomException e) { // ... } } }

    What I'd expect to happen: No changes to the database and no exception visible to the user.

    What happens: No changes to the database but the app crashes with:

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

    It's correctly setting the transaction to rollbackOnly but why is the rollback crashing with an exception?

    解决方案

    My guess is that ServiceUser.method() is itself transactional. It shouldn't be. Here's the reason why.

    Here's what happens when a call is made to your ServiceUser.method() method:

  • the transactional interceptor intercepts the method call, and starts a transaction, because no transaction is already active
  • the method is called
  • the method calls MyService.doSth()
  • the transactional interceptor intercepts the method call, sees that a transaction is already active, and doesn't do anything
  • doSth() is executed and throws an exception
  • the transactional interceptor intercepts the exception, marks the transaction as rollbackOnly, and propagates the exception
  • ServiceUser.method() catches the exception and returns
  • the transactional interceptor, since it has started the transaction, tries to commit it. But Hibernate refuses to do it because the transaction is marked as rollbackOnly, so Hibernate throws an exception. The transaction interceptor signals it to the caller by throwing an exception wrapping the hibernate exception.
  • Now if ServiceUser.method() is not transactional, here's what happens:

  • the method is called
  • the method calls MyService.doSth()
  • the transactional interceptor intercepts the method call, sees that no transaction is already active, and thus starts a transaction
  • doSth() is executed and throws an exception
  • the transactional interceptor intercepts the exception. Since it has started the transaction, and since an exception has been thrown, it rollbacks the transaction, and propagates the exception
  • ServiceUser.method() catches the exception and returns
  • 更多推荐

    无法提交JPA事务:标记为rollbackOnly的事务

    本文发布于:2023-10-05 10:39:14,感谢您对本站的认可!
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:事务   标记   JPA   rollbackOnly

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!