Search code examples
javaspringhibernatejpaspring-transactions

Continue with transaction after exception - JPA


I am using JPA with Spring. I am trying to do batch import. If there is problem with batch import then I would like to insert individually, and if this fails also then I would like to save to duplicates table. I wrote a logic for this but I get this error everytime:

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

Mine setting for JPA are like this:

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

I get entity manager like this

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

  protected EntityManager em() {
    return em;
  }

my import method is:

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

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

and saveBatch method from repository:

  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
        }
      }
    }
  }

I tried setting dontRollbackOn but I can't get past this exception. I found some other similar threads but none helped me.


Solution

  • I only managed to fix this by creating another bean containing batch import method. So after that Spring can intercept the call from this bean and start a new transaction.