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

内部事务(REQUIRES_NEW)引发异常时外部事务回滚

颜鸿云
2023-03-14

我有办法:

  @Transactional
  public void importChargesRequest() {
  ...
   for (Charge charge : charges) {

      try {
        Charge savedCharge = saveCharge(charge);
      } catch (Exception e) {
        log.error(e.getMessage());
      }
    }
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
  public Charge saveCharge(Charge charge) {
    return chargesRepository.saveAndFlush(charge);
  }
Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit
@Service
public class TestService {

  private final TestDao testDao;

  public TestService(TestDao testDao) {
    this.testDao = testDao;
  }

  @Transactional
  public void saveTest() {
    for (int i = 0; i < 100; i++) {
      Test test = new Test();
      if (i == 10 || i == 20) {
        test.setName("123");
      } else {
        test.setName(UUID.randomUUID().toString());
      }
      testDao.save(test);
    }
  }
} 

和每个内部事务的另一个bean:

@Slf4j
@Component
@Repository
public class TestDao {

  @PersistenceContext
  private EntityManager entityManager;

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void save(Test test) {
    entityManager.persist(test);
  }
}

当我第一次尝试保存时,我有20行DB。每次下一次保存,我得到+10行。名称具有约束。当我得到错误时,事务是提交而不是继续。每次保存后我都会等待98行。

共有1个答案

祁承嗣
2023-03-14

如果SaveCharge是与ImportChargesRequest相同bean中的方法,则忽略@Transactional注释,并且saveAndFlush在相同(外部)事务中工作。(我敢肯定,当您使用代理/拦截器来管理事务时,情况就是如此。我敢肯定,当使用基于AspectJ的事务拦截时,情况也是如此)。

通常,只有当异常一直冒泡到外部方法(标记@transaction的方法)时,事务才会被标记为回滚,但我怀疑存储库或事务管理器本身(hibernate会话)由于违反约束而直接将事务标记为回滚。

解决方案是将saveCharge移动到另一个bean,并使用importChargesRequest-method将该bean注入到该bean中。

@Service
public class ChargesDataService{

  @Autowire
  private ChargesRepository chargesRepository;

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public Charge saveCharge(Charge charge) {
    return chargesRepository.saveAndFlush(charge);
  }
}

@RestController
html" target="_blank">public class ChargesController{

  @Autowire
  private ChargesDataService chargesDataService;

  @Transactional
  public void importChargesRequest() {

   for (Charge charge : charges) {

      try {
        Charge savedCharge = chargesDataService.saveCharge(charge);
      } catch (Exception e) {
        log.error(e.getMessage());
      }
    }
  }
}

补遗:注释被忽略,因为您不再通过bean实例的代理,这意味着没有拦截器被调用,这意味着没有地方处理新事务。您可以通过在saveCharge方法中设置断点并查看StackTrace^来检查是否存在这种情况。寻找类似事务拦截器invokeWithIntransaction的方法。

^您还可以创建一个新异常,调用fillInStacktrace,然后记录/打印异常(包括其StackTrace)。

 类似资料:
  • 您能否帮助解决Resin+Oracle上XA事务的问题: 我们有WebApp,它必须执行涉及Oracle11.2.0.1和EHCache2.7的业务事务。(实际上可能有各种组合--两个不同的Oracle数据源(不同的模式),带有/不带有Ehcache,等等)。这就是从普通JDBC使用切换到JTA事务划分的原因。 > 在外部事务中使用Ehcache访问,在内部事务中只使用DB访问,即使在内部事务中使

  • 我使用的是Spring3.0.5和Hibernate3.6。在我的项目中,有一个场景,我必须回滚在抛出的任何异常或错误发生的事务。这是示例代码,除了当我抛出异常时事务不会回滚之外,一切都很好,但是如果抛出任何异常,比如mysql.IntegrityConstraintException,那么事务会回滚,为什么在我的情况下没有发生这种情况? hibernate.cfg 因此,正如我所说,我的问题是,

  • 我正在尝试使用Hibernate保存数据。一切都发生在同一会话中。逻辑如下: 1)开始交易并尝试保存: 2) 如果新记录违反完整性约束,请在外包装方法中捕获异常,打开另一个事务并查询更多数据 问题是当第二个事务执行时query.list它会抛出一个应该与前一个事务链接的异常。 SQLIntegrityConstraintViolationException:ORA-00001:唯一约束 我应该从另

  • 我在tomcat服务器中使用具有多个数据源配置的JTA原子事务。有时我会遇到以下异常: JTA事务意外回滚(可能是由于超时);嵌套的异常是javax。交易回滚异常:事务被设置为仅回滚 出现这种异常的原因是什么?

  • 我有Spring > 不应该失败主事务,在我的例子中是cteateSmth() 如果失败,应该回滚它自己的事务 service1.cteatsmth(); 在上面的例子中,即使尝试对cretePartA()进行捕获包装,整个cteateSmth()事务也将回滚。 我尝试使用REQUIRES_NEW来实现这一点,但在这种情况下似乎无法回滚cretePartA()操作。 我试图不为cretePartA