HibernateTransactionManager @Transactional(propagation = REQUIRES_NEW)无法打开2个会话

时间:2017-09-22 10:56:02

标签: java spring hibernate jpa transactional

有一个批处理作业看起来像这样:

@Transactional
public void myBatchJob() {
    // retrieves thousands of entries and locks them 
    // to prevent other jobs from touthing this dataset
    entries = getEntriesToProcessWithLock(); 
    additional = doPrepWork(); // interacts with DB
    processor = applicationContext.getBean(getClass());
    while (!entries.isEmpty()) {
        result = doActualProcessing(entries, additional); // takes as many entries as it needs; removes them from collection afterwards
        resultDao.save(result);
    }
}

但是,如果entries集合足够大,我偶尔会收到以下错误。

  

ORA-01000:超出最大打开游标数

我决定责怪doActualProcessing()save()方法,因为它们最终会在一次交易中创建数百个blob。

显而易见的出路似乎是将处理拆分为多个事务:一个用于获取和锁定条目,另一个用于处理和持久化。像这样:

@Transactional
public void myBatchJob() {
    // retrieves thousands of entries and locks them 
    // to prevent other jobs from touthing this dataset
    entries = getEntriesToProcessWithLock(); 
    additional = doPrepWork(); // interacts with DB
    processor = applicationContext.getBean(getClass());
    while (!entries.isEmpty()) {
        processor.doProcess(entries, additional);
    }
}

@Transactional(propagation=REQUIRES_NEW)
public void doProcess(entries, additional) {
    result = doActualProcessing(entries, additional); // takes as many entries as it needs; removes them from collection afterwards
    resultDao.save(result);
}

现在每当调用doProcess时我都会:

  

引起:org.hibernate.HibernateException:非法尝试将代理与两个打开的会话相关联

如何让HibernateTransactionManager执行REQUIRES_NEW javadoc建议的内容:暂停当前事务并开始新事务?

1 个答案:

答案 0 :(得分:2)

在我看来,问题在于您已检索到顶级事务中的实体,并且当它们仍与该事务关联时,您尝试将它们(代理)传递给将在单独事务中处理的方法。

我认为您可以尝试两种选择:

1)在假装processor.doProcess(entries, additional);之前分离实体:

session.evict(entity); // loop through the list and do this

然后在内部事务内部尝试合并:

session.merge(entity);

2)第二个选项是检索{而不是getEntriesToProcessWithLock中的实体。然后你将传递普通的原始字段,这些字段不会导致代理问题。然后,您将在内部事务中检索正确的实体。