我目前有一个用例,其中如果我的用户手动插入要读取到数据库中的数据文件,我需要判断数据是否存在于数据库中.如果是,我想删除它,然后处理并保存新文件.这样做的问题是,我的方法被标记为@Transaction,因此即使运行了删除方法,它们也不会在调用保存方法之前提交,这违反了导致回滚的唯一约束.

我try 了每种传播级别,还try 将它们拆分成两个独立的事务,我的控制器逐个调用它们,而它们不会相互调用.

错误:org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only年前

代码:

 @Transactional
  public void saveAllPositionData(InputStream is) throws IOException {

    log.info("Parsing position data...");
    ParsingResult parsingResult = positionParser.parse(is);
    if (!parsingResult.getPositions().isEmpty()) {
      LocalDate businessDate = parsingResult.getPositions().get(0).getBusinessDate();
      overwriteData(businessDate);
    }

    try {
      positionRepo.saveAll(bpsParsingResult.getPositions()); // UNIQUE CONSTRAINT FAILS HERE CAUSING ROLLBACK
      priceRepo.saveAll(parsingResult.getPrices());

      for (PositionTable position : parsingResult.getPositions()) {
        if (position.getNumberOfMemos() > 0) memoRepo.saveAll(position.getCorrespondingMemos());
      }
    } catch (Exception e) {
      log.warn("Invalid data returned from BPS parsing job: {}", e.getMessage());
    }
  }

  @Transactional(propagation = Propagation.NESTED) // Tried Propagation.* and no Annotation
  public void overwriteData(LocalDate businessDate) {
    if (memoRepo.countByBusinessDate(businessDate) > 0) {
      log.warn(
              "Memo record(s) found by {} business date. Existing data will be overridden.",
              businessDate);
      memoRepo.deleteByBusinessDate(businessDate);
    }
    if (positionRepo.countByBusinessDate(businessDate) > 0) {
      log.warn(
          "Position record(s) found by {} business date. Existing data will be overridden.",
          businessDate);
      positionRepo.deleteByBusinessDate(businessDate);
    }
    if (priceRepo.countByBusinessDate(businessDate) > 0) {
      log.warn(
          "Price record(s) found by {} business date. Existing data will be overridden.",
          businessDate);
      priceRepo.deleteByBusinessDate(businessDate);
    }
  }

推荐答案

UnexpectedRollbackException通常发生在内部的@Transactional方法抛出异常,但外部的@Transactional方法捕捉到该异常,但不会重新引发它.(有关更多详细信息,请参见this).JpaRepository上的方法实际上有@Transactional个注释.现在在saveAllPositionData()中,一些方法调用了JpaRepository抛出异常,但您捕获了它,而不是重新引发它,所以它导致了UnexpectedRollbackException.

此外,如果您从内部类self 调用@Transactional方法,则它不起作用.这意味着overwriteData()上的@Transactional在您的代码中不起作用.(有关更多详细信息,请参阅方法可见性和第docs中的第@Transactional节)

这样做的问题是我的方法被标记为@Transaction,所以即使 尽管Delete方法已运行,但它们不会在 调用了Save方法,该方法违反了唯一约束 回滚

在调用Delete方法后,您可以try 在JpaRepository上调用flush().它将把到目前为止收集的所有挂起的SQL更改应用到数据库,但不会提交事务.因此,只有涉及的事务才会看到记录被删除,这样以后在同一事务中插入数据时,就不会遇到违反唯一约束的情况.

Java相关问答推荐

找到允许的最大底片

如何在SystemiccationRetryListenerSupport中获得类级别的spring retryable annotation中指定的标签?

同时运行JUnit测试和Selenium/Cucumber测试时出现问题

根据对象和值的参数将映射<;T、值&>转换为列表<;T&>

基本时态运算的ISO-8601周数据表示法

Jlink选项&-strie-ative-Commands";的作用是什么?

GSON期间的Java类型擦除

如何使用带有谓词参数的方法,而不使用lambda表达式

测试容器无法加载类路径初始化脚本

我如何解释这个错误?必需类型:供应商R,提供:收集器对象,捕获?,java.util.List java.lang.Object>>

未找到适用于响应类型[类java.io.InputStream]和内容类型[Text/CSV]的HttpMessageConverter

SpringBoot:在条件{Variable}.isBlank/{Variable}.isEmpty不起作用的情况下进行路径变量验证

JNI:将代码打包成自包含的二进制文件

泛型与泛型问题的完美解决方案?

Cucumber java-maven-示例表-未定义一步

如何使用stream.allMatch()为空流返回false?

ResponseEntity.控制器截断响应的JSON部分

JavaFX中ListView中的问题

如何使用java区分以下结果

为什么 Random() 的行为不符合预期?