当前位置: 首页 > 知识库问答 >
问题:

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

白念
2023-03-14

我在一个应用程序中使用Spring和Hibernate,我在处理事务时遇到了问题。

我有一个服务类,它从数据库加载一些实体,修改它们的一些值,然后(当一切都有效时)将这些更改提交给数据库。如果新值无效(我只能在设置它们后检查),我不想保留更改。为了防止Spring/Hibernate保存更改,我在方法中抛出一个异常。但是,这会导致以下错误:

Could not commit JPA transaction: Transaction marked as rollbackOnly

这就是服务:

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

  }
}

我就是这样调用它的:

class ServiceUser {
  @Autowired
  private MyService myService;

  public void method() {
    try {
      myService.doSth();
    } catch (MyCustomException e) {
      // ...
    }        
  }
}

我希望发生的事情是:数据库没有变化,用户也没有可见的异常。

发生的情况:数据库没有变化,但应用程序崩溃:

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

它正确地将事务设置为rollbackOnly,但为什么回滚会崩溃并出现异常?

共有1个答案

盛超
2023-03-14

我的猜测是serviceuser.method()本身就是事务性的。不应该是的。原因如下。

以下是调用serviceuser.method()方法时发生的情况:

  1. 事务拦截器拦截方法调用,并启动事务,因为没有事务是活动的
  2. 该方法称为
  3. 该方法调用myservice.dosth()
  4. 事务拦截器拦截方法调用,查看事务已经处于活动状态,并且不执行任何操作
  5. dosth()执行并抛出异常
  6. 事务拦截器拦截异常,将事务标记为rollbackOnly,并传播异常
  7. serviceuser.method()捕获异常并返回
  8. 事务拦截器,因为它已经启动了事务,所以尝试提交它。但是Hibernate拒绝这样做,因为事务被标记为rollbackOnly,所以Hibernate抛出一个异常。事务拦截器通过抛出包装hibernate异常的异常向调用方发出信号。
  1. 该方法称为
  2. 该方法调用myservice.dosth()
  3. 事务拦截器拦截方法调用,发现没有事务已经处于活动状态,因此启动事务
  4. dosth()执行并抛出异常
  5. 事务拦截器拦截异常。因为它已经启动了事务,并且引发了异常,所以它回滚事务,并传播异常
  6. serviceuser.method()捕获异常并返回
 类似资料:
  • 问题内容: 我在正在使用的一个应用程序中使用Spring和Hibernate,但是在处理事务时遇到了问题。 我有一个服务类,该类从数据库中加载一些实体,修改它们的一些值,然后(当所有内容都有效时)将这些更改提交给数据库。如果新值无效(我只能在设置它们后检查),但我不想保留更改。为了防止Spring / Hibernate保存更改,我在方法中抛出异常。但是,这导致以下错误: 这是服务: 这就是我调用

  • 我有一个应用程序通过jpa对各种数据库表进行大量写入。其中一个写入可能会导致乐观锁异常。如果抛出一个,没什么大不了的,我希望事务的其余部分提交。 我通过以下方式查看了Spring事务上的无回滚功能: 我的应用程序捕获了实体的合并方法周围的OLException,该方法将引发此异常,但事务仍会回滚。我做了一些挖掘,看看发生了什么,在JpaTransactionManager的doCommit方法中,

  • 我在使用Hibernate执行数据库更新时遇到了一个问题。当尝试repository.add(Object)操作时,它会给出一个验证异常。 我已经在模型类上添加了验证,但是我试图插入的值似乎满足了要求,所以我不知道问题出在哪里。 如果删除验证注释,repository.add(object)就可以成功完成,即。 好心看看有没有什么建议,提前谢谢。 MySQL(8.0.17)模式 Hibernate

  • 我的路线如下 我知道(A)处的JMS消费者将在每次轮询时分叉JMS事务,并附加到线程。(B)中的事务处理节点也将在交换到达那里并连接到线程后分叉JPA事务。 请在下面找到我的问题: > < li >能否将两个不同的事务附加到一个线程上(如上所示)? < li >如果是,哪一个应该被停职? < li> 上述路由的提交和回滚顺序应该是什么? 注:我没有从骆驼在行动第二版中找到任何明显的答案,所以请指导

  • 我正在为应用程序使用Spring data JPA的存储库。目前,我正在使用spring data jpa存储库默认提供的基本CRUD操作,对于复杂的join查询,我正在编写定制的JPQL查询,如下所示: 在我的服务类中,我自动生成这个存储库并执行DB操作。 目前,我只是将标记为。 我是否也应该将方法标记为?因为它只执行读取操作。 我是否也应该将标记为事务性(readOnly=true)?我读到所

  • 我正在使用手动事务时插入/更新3个表。我想在事务提交后立即插入到历史表中。这意味着有3个操作(针对每个表),只有在提交这些操作之后,我才希望调用一个方法。 这是我的代码: 有什么post commit方法吗?如何在提交之后而不是持久之后调用方法?