HibernateTransactionManager @Transactional(propagation=REQUIRES_NEW) 无法打开 2 个会话
HibernateTransactionManager @Transactional(propagation=REQUIRES_NEW) cannot open 2 sessions
有一个批处理作业如下所示:
@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: maximum open cursors exceeded
我决定责怪 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
时,我都会得到:
Caused by: org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
如何让 HibernateTransactionManager
执行 REQUIRES_NEW
javadoc 建议的操作:暂停当前事务并开始新事务?
在我看来,问题在于您已经检索到顶级交易中的实体,虽然它们仍然与该交易相关联,但您尝试将它们(代理)传递给将在单独的处理中处理的方法交易。
我认为您可以尝试两种选择:
1) 在调用之前分离实体 processor.doProcess(entries, additional);
:
session.evict(entity); // loop through the list and do this
然后内部事务尝试合并:
session.merge(entity);
2) 第二个选项是检索 ID 而不是 getEntriesToProcessWithLock
中的实体。然后您将传递不会导致代理问题的普通原始字段。然后,您将在内部事务中检索适当的实体。
有一个批处理作业如下所示:
@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: maximum open cursors exceeded
我决定责怪 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
时,我都会得到:
Caused by: org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
如何让 HibernateTransactionManager
执行 REQUIRES_NEW
javadoc 建议的操作:暂停当前事务并开始新事务?
在我看来,问题在于您已经检索到顶级交易中的实体,虽然它们仍然与该交易相关联,但您尝试将它们(代理)传递给将在单独的处理中处理的方法交易。
我认为您可以尝试两种选择:
1) 在调用之前分离实体 processor.doProcess(entries, additional);
:
session.evict(entity); // loop through the list and do this
然后内部事务尝试合并:
session.merge(entity);
2) 第二个选项是检索 ID 而不是 getEntriesToProcessWithLock
中的实体。然后您将传递不会导致代理问题的普通原始字段。然后,您将在内部事务中检索适当的实体。