我尝试本地化以下代码段中的错误:
Query bookLogs = session.createQuery("FROM BookLog log");
for (Iterator it = bookLogs.iterate(); it.hasNext();) {
BookLog bookLog = (BookLog) it.next();
bookNo = bookLog.getNo();
...
session.delete(bookLog);
session.flush();
}
在bookLog.getNo()中不常发生以下异常:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [de.store.Books.BookLog#2343]
我认为在删除db条目时会发生冲突,而迭代器不会通过调用它来调整.remove()。
BookLog不引用任何表格,因此其映射很简单。
答案 0 :(得分:0)
当Query.interate()
返回代理迭代器时,只有id
个实体被提取。
执行1 + N个SQL查询。第一个查询只返回所有记录的标识符,并且当迭代返回的迭代器时,每次执行包含WHERE id = N的WHERE子句的单独SQL查询。如果记录存在于缓存中,则执行第一个查询,不执行其余N个查询,并从缓存中获取记录。
所以这是并发修改问题。在执行查询时
for (Iterator it = bookLogs.iterate(); it.hasNext();) {
给定BookLog
并将其id
返回到迭代器中。在迭代时,为每个
bookNo = bookLog.getNo()
执行单独的SELECT
查询,但在此时,整个表可能已被另一个并发操作修改。给定id
的行不再存在,并抛出异常。
为避免这种情况,您必须使用正确的transaction-isolation
或使用Query.getResultList()
。这将在单个查询中返回所有结果。但是,无法保证(再次)当您尝试delete
返回的实体时,它仍然会在数据库中。