【发布时间】:2014-09-01 09:18:19
【问题描述】:
我有以下问题:
当实体应保存在数据库中时,我有一个应用程序将 DatabaseJob 发送到单独线程中的队列。当队列有作业时,这个工作线程从队列中取出第一个作业并使用 Hibernate 保存它。一般来说,这工作得很好。
我遇到的问题是在尝试保存大型集合(1000+)条目时出现的。在 Hibernate 尝试将其刷新到数据库时,可能会修改集合,从而导致以下ConcurrentModificationException。
2014-09-01 10:37:57,301 ERROR [DatabaseManager] [Thread: database-message-queue] Hibernate - Unhandled Exception during saving
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:711)
at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:734)
at org.hibernate.collection.internal.PersistentSet.getSnapshot(PersistentSet.java:96)
at org.hibernate.engine.spi.CollectionEntry.afterAction(CollectionEntry.java:246)
at org.hibernate.action.internal.CollectionUpdateAction.execute(CollectionUpdateAction.java:105)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
通过使用Collections.synchronizeXXX,我使用的所有集合都可以安全地进行并发访问,但对于迭代它必须手动同步。
有什么方法可以分别使用线程安全的迭代器来同步 Hibernate 的集合访问?我已经尝试过使用org.hibernate.usertype.UserCollectionType,但也没有用。
否则我想我可能必须在将实体添加到数据库队列之前复制它们,但我希望有一种更简单的方法。
提前非常感谢, 本杰明·高尼茨
UPDATE 1 -> 相关代码块(为简单起见删除了异常处理)
private void processHibernateSaves() {
if (!savesHibernate.isEmpty()) {
Iterator<DatabaseJobEvent> jobIter = savesHibernate.iterator();
while (jobIter.hasNext()) {
DatabaseJobEvent job = jobIter.next();
Session session = HibernateUtil.currentSession();
tx = session.beginTransaction();
for (PersistentObject obj : job.getObjects()) {
if (obj.isSavedInDatabase()) {
session.update(obj);
} else {
session.save(obj);
}
}
tx.commit(); //<-- Error is thrown at this point
session.clear();
for (PersistentObject obj : job.getObjects()) {
synchronized (obj) {
obj.setSavedInDatabase(true);
}
}
job.setExecuted(true);
jobIter.remove();
}
}
}
PersistentObject 不是集合本身,它包含作为字段的集合。
【问题讨论】:
-
向我们展示你保存集合的代码
-
请贴出相关代码
-
Collections.synchronizeXXX 是不够的。请改用 java.util.concurrent.CopyOnWriteArrayList。
-
保存期间也最好禁止修改集合。
标签: java multithreading hibernate