我想迭代数据库中的记录并更新它们。但是,由于更新需要花费一些时间并且容易出错,因此我需要a)不要让db等待(例如使用ScrollableResults
)和b)在每次更新后提交。
第二件事是这是在多个线程中完成的,所以我需要确保如果线程A正在处理记录,则线程B将获得另一个线程。
如何通过hibernate明智地实现这一点?
为了更好地了解,以下代码将由多个线程执行,其中所有线程共享RecordIterator
的单个实例:
Iterator<Record> iter = db.getRecordIterator();
while(iter.hasNext()){
Record rec = iter.next();
// do something lengthy here
db.save(rec);
}
所以我的问题是如何实现RecordIterator
。如果每next()
我执行一次查询,如何确保我不会两次返回相同的记录?如果我不这样做,使用哪个查询来返回分离的对象?一般方法是否存在缺陷(例如,每个线程使用一个RecordIterator
并让db以某种方式处理同步)?附加信息:有许多记录可以在本地保存它们(例如,在一组处理过的记录中)。
更新:由于整个过程需要一些时间,因此记录状态可能会发生变化。由于查询结果的排序可能会发生变化。我想要解决这个问题,我必须在数据库中标记记录,一旦我将它们返回进行处理......
答案 0 :(得分:2)
嗯,如何在某个有界阻塞队列中从读取器线程中推送对象,并让更新程序线程从该队列中读取。
在您的阅读器中,使用setFirstResult / setMaxResults进行一些分页。例如。如果队列中最多有1000个元素,请一次填充500个元素。当队列已满时,下一次推送将自动等待,直到更新者获取下一个元素。
答案 1 :(得分:0)
我的建议是,因为你正在共享一个主迭代器的实例,就是使用一个共享的Hibernate事务来运行你的所有线程,一开始就有一个加载,最后有一个大的保存。您将所有数据加载到一个“Set”中,您可以使用您的线程进行迭代(请注意锁定,因此您可能希望为每个线程拆分一个部分,或以某种方式管理共享资源以便您不要重叠)。
Hibernate解决方案的优点在于,记录不会立即保存到数据库中,因为您正在使用事务,并存储在hibernate的缓存中。然后在最后他们都会立刻被写回数据库。这将节省您担心的那些昂贵的数据库写入,而且它为您提供了在每次迭代时使用的实际对象,而不仅仅是数据库行。
我在您的更新中看到记录的状态可能会在处理过程中发生变化,这可能会导致问题。如果这是一个持续运行的进程或长时间运行,那么我使用hibernate解决方案的建议是在较小的集合中工作,是的,添加一个标记来标记已更新的记录,这样当你移动到下一个集合时可以拿起那些没有碰过的。