异常后继续交易 - JPA
Continue with transaction after exception - JPA
我在 Spring 中使用 JPA。我正在尝试批量导入。如果批量导入有问题,那么我想单独插入,如果这也失败了,那么我想保存到重复项 table。我为此写了一个逻辑,但我每次都会收到这个错误:
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 但我无法通过此异常。我发现了一些其他类似的主题,但 none 帮助了我。
如果您的方法具有@Transactional 注释,则在您的方法中发生任何异常都会将周围的事务标记为回滚。
您可以为@Transactional 注释添加一个属性以防止它回滚,例如:@Transactional(noRollbackFor=Exception.class)。 Spring 运行时异常的所有子类型的回滚事务。
如果你想在捕获时做某事,你应该尝试在新的 transaction.But 中进行,请记住 spring 中的自我调用不受支持,你不能只从方法 1 调用事务方法 2 ,您应该从 spring 上下文获取当前服务并调用方法 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
}
}
}
我只能通过创建另一个包含批量导入方法的 bean 来解决这个问题。所以之后 Spring 可以拦截来自这个bean的调用并开始一个新的事务。
我在 Spring 中使用 JPA。我正在尝试批量导入。如果批量导入有问题,那么我想单独插入,如果这也失败了,那么我想保存到重复项 table。我为此写了一个逻辑,但我每次都会收到这个错误:
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 但我无法通过此异常。我发现了一些其他类似的主题,但 none 帮助了我。
如果您的方法具有@Transactional 注释,则在您的方法中发生任何异常都会将周围的事务标记为回滚。
您可以为@Transactional 注释添加一个属性以防止它回滚,例如:@Transactional(noRollbackFor=Exception.class)。 Spring 运行时异常的所有子类型的回滚事务。
如果你想在捕获时做某事,你应该尝试在新的 transaction.But 中进行,请记住 spring 中的自我调用不受支持,你不能只从方法 1 调用事务方法 2 ,您应该从 spring 上下文获取当前服务并调用方法 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
}
}
}
我只能通过创建另一个包含批量导入方法的 bean 来解决这个问题。所以之后 Spring 可以拦截来自这个bean的调用并开始一个新的事务。