java - 异常后继续交易 - JPA

标签 java spring hibernate jpa spring-transactions

我正在将 JPA 与 Spring 结合使用。我正在尝试批量导入。如果批量导入有问题那么我想单独插入,如果这也失败那么我想保存到重复表。我为此写了一个逻辑,但每次都会收到此错误:

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

我的 JPA 设置是这样的:

@Bean(name = "dataSource", destroyMethod = "")
  public DataSource getDataSource() {
    return new JndiDataSourceLookup().getDataSource(props.getDbJndiName());
  }

  @Bean
  public JpaVendorAdapter getHibernateJpaVendorAdapter() {
    return new HibernateJpaVendorAdapter();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() {
    LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean();
    lcemfb.setDataSource(getDataSource());
    lcemfb.setPersistenceUnitName("MyPU");
    lcemfb.setPackagesToScan("com.project");
    lcemfb.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
    lcemfb.setJpaProperties(getHibernateProperties());
    return lcemfb;
  }

  @Bean
  public Properties getHibernateProperties() {
    Properties jpaProperties = new Properties();
    jpaProperties.put(DIALECT, "org.hibernate.dialect.Oracle10gDialect");
    jpaProperties.put(SHOW_SQL, true);
    jpaProperties.put(AUTOCOMMIT, true);
    jpaProperties.put(FORMAT_SQL, true);
    jpaProperties.put(USE_SQL_COMMENTS, true);
    jpaProperties.put(STATEMENT_BATCH_SIZE, 20);
    jpaProperties.put(ORDER_INSERTS, true);
    jpaProperties.put("hibernate.ejb.entitymanager_factory_name", "MyEM");
    return jpaProperties;
  }

  @Bean
  public JpaTransactionManager getTransactionManager() {
    return new JpaTransactionManager(getEntityManagerFactoryBean().getObject());
  }

  @Bean
  public PersistenceExceptionTranslationPostProcessor getPersistenceExceptionTranslationPostProcessor() {
    return new PersistenceExceptionTranslationPostProcessor();
  }

我得到这样的实体管理器

@PersistenceContext(unitName = "MyPU")
  private EntityManager em;

  protected EntityManager em() {
    return em;
  }

我的导入方法是:

  @Override
  @Transactional
  public void importBusinessFile(MultipartFile file)
      throws GeneralException, IOException {
    // process file

    //save batch
    dealsRepository.saveBatch(deals);
  }

和存储库中的 saveBatch 方法:

  public void saveBatch(List<Deal> list) {
    for (Deal deal : list) {
      em().persist(deal);
    }

    try {
      em().flush();
      em().clear();
    } catch (Exception e) {
      log.info("Duplicates detected, save individually.", e);

      for (Deal deal : list) {
        try {
          save(deal);
        } catch (Exception ex) {
          log.error("Problem saving individual deal", e);
          // TODO write to duplicates
        }
      }
    }
  }

我尝试设置 dontRollbackOn 但我无法通过此异常。我发现了其他一些类似的线程,但没有一个对我有帮助。

最佳答案

如果你的方法有@Transactional注解,你的方法中发生的任何异常都会将周围的事务标记为回滚。

您可以为@Transactional 注释添加一个属性以防止它回滚,例如:@Transactional(noRollbackFor=Exception.class)。所有子类型的运行时异常的 Spring 回滚事务。

如果你想在捕获时做一些事情,你应该尝试在新的事务中做它。但是请记住,在 spring 中不支持自调用,你不能只从方法 1 调用事务方法 2,你应该从 spring 上下文中获取 current服务和调用方法2。

PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions. See Spring’s DataSourceTransactionManager.


简单的变体:

  @Autowired
  private ApplicationContext context.

  @Override
  @Transactional
  public void importBusinessFile(MultipartFile file)
      throws GeneralException, IOException {
    // process file

    try{
       dealsRepository.saveBatch(deals);
       //in  case fail-transaction for saveBatch is rollback main transactio is active
    }catch(Exception e){
        context.getBean(curent serivce).tryReSaveBatch(deals);
       //in  case fail - transaction for tryReSaveBatchis rollback , 
main transactio is active
    }
     // main transaction commited
  }

@Transactional(propagation = NESTED)
public void saveBatch(List<Deal> list) {
    for (Deal deal : list) {
      em().persist(deal);
    }
  }

@Transactional(propagation = NESTED)
public void tryReSaveBatch(List<Deal> list) {
for (Deal deal : list) {
        try {
          save(deal);
        } catch (Exception ex) {
          log.error("Problem saving individual deal", e);
          // TODO write to duplicates
        }
      }
  }

关于java - 异常后继续交易 - JPA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44887675/

相关文章:

java - 如何通用设置属性配置?

java - 警告 : Couldn't read data from file "image.jpg", 这会导致空 POST

java - 在 Spring MVC + Hibernate 中自动生成唯一的随机字符串

java - 缩放函数/方法的参数/输入数量

java - 如果一个类只委托(delegate)而什么都不做,那么它有什么用呢?

java - 如果我使用 HTTPS,如何获取客户端的 IP 地址?

java - 带有 JPA : hibernate access without schema spécified in entity 的 Hibernate 5

spring - 无法让 OpenEntityManagerInViewFilter 在 JBoss 6.1 中工作

java - 表格 View 刷新问题

java - 具有不同泛型的方法参数是否使方法具有不同的签名?