无法提交 JPA 事务:事务标记为 rollbackOnly [英] Could not commit JPA transaction: Transaction marked as rollbackOnly

查看:53
本文介绍了无法提交 JPA 事务:事务标记为 rollbackOnly的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我正在开发的应用程序之一中使用 Spring 和 Hibernate,但在处理事务时遇到了问题.

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.

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

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

这就是服务:

@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

正确地将事务设置为 rollbackOnly 但为什么回滚会因异常而崩溃?

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

推荐答案

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

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

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

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

  1. 事务拦截器拦截方法调用,并启动一个事务,因为没有事务已经处于活动状态
  2. 方法被调用
  3. 该方法调用 MyService.doSth()
  4. 事务拦截器拦截方法调用,看到一个事务已经处于活动状态,不做任何事情
  5. doSth() 被执行并抛出异常
  6. 事务拦截器拦截异常,将事务标记为rollbackOnly,并传播异常
  7. ServiceUser.method() 捕获异常并返回
  8. 事务拦截器,因为它已经启动了事务,所以尝试提交它.但是Hibernate拒绝这样做,因为事务被标记为rollbackOnly,所以Hibernate抛出异常.事务拦截器通过抛出一个包含休眠异常的异常来向调用者发出信号.

现在如果 ServiceUser.method() 不是事务性的,会发生以下情况:

Now if ServiceUser.method() is not transactional, here's what happens:

  1. 方法被调用
  2. 该方法调用 MyService.doSth()
  3. 事务拦截器拦截方法调用,看到没有事务已经处于活动状态,从而启动一个事务
  4. doSth() 被执行并抛出异常
  5. 事务拦截器拦截异常.由于它已经启动了事务,并且由于抛出了异常,它回滚事务,并传播异常
  6. ServiceUser.method() 捕获异常并返回

这篇关于无法提交 JPA 事务:事务标记为 rollbackOnly的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆