hibernate批量查询
如果需要从Java处理大型数据库结果集,则可以选择JDBC,以提供所需的低级控制。 另一方面,如果您已在应用程序中使用ORM,则回退到JDBC可能会带来一些额外的麻烦。 在导航域模型时,您将失去诸如乐观锁定,缓存,自动获取之类的功能。 幸运的是,大多数ORM,例如Hibernate,都有一些选择来帮助您。 虽然这些技术不是新技术,但有两种可能可供选择。
一个简化的例子; 假设我们有一个表(映射到类'DemoEntity'),具有100.000条记录。 每个记录由一个列(映射到DemoEntity中的属性“ property”)组成,其中包含一些大约2KB的随机字母数字数据。
JVM与-Xmx250m一起运行。 假设250MB是可以分配给系统上JVM的总最大内存。 您的工作是读取表中当前的所有记录,进行一些未进一步指定的处理,最后存储结果。 我们假设批量操作产生的实体没有被修改。 首先,我们将首先尝试显而易见的方法,即执行查询以简单地检索所有数据:
new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
Session session = sessionFactory.getCurrentSession();
List<DemoEntity> demoEntitities = (List<DemoEntity>) session.createQuery('from DemoEntity').list();
for(DemoEntity demoEntity : demoEntitities){
//Process and write result
}
return null;
}
});
几秒钟后:
Exception in thread 'main' java.lang.OutOfMemoryError: GC overhead limit exceeded
显然,这不会削减。 为了解决这个问题,我们将切换到Hibernate可滚动结果集,这可能是大多数开发人员都知道的。 上面的示例指示hibernate执行查询,将整个结果映射到实体并返回它们。 使用滚动结果集时,记录一次转换为一个实体:
new TransactionTemplate(txManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
Session session = sessionFactory.getCurrentSession();
ScrollableResults scrollableResults = session.createQuery('from DemoEntity').scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
while (scrollableResults.next()) {
if (++count > 0 && count % 100 == 0) {
System.out.println('Fetched ' + count + ' entities');
}
DemoEntity demoEntity = (DemoEntity) scrollableResults.get()[0];
//Process and write result
}
return null;
}
});
运行此后,我们得到:
...
Fetched