何时使用spring / hibernate启动批处理作业的新会话/事务以及何时提交/刷新会话的最佳实践?

时间:2011-06-22 03:22:48

标签: java hibernate spring session transactions

我在春天设置了一个tx-advice,用于围绕我的Service方法包装事务。所以说在我的批处理类中,我调用一个服务方法来加载一个对象列表并将其返回给我的批处理类。然后在我的批处理类中,我调用一个服务方法来处理每个对象。但是,如果该服务方法试图访问该对象的延迟加载属性,我会收到一个延迟加载异常,因为该对象列表加载了不同的hibernate会话。

所以这可能不是最优的方法是 - 批处理类只调用一个服务来加载那些对象的所有ID(长值) - 我们将这个ID传递给一个服务方法,它将加载来自DB的对象,然后对其进行处理。

对此的想法?

我遇到的另一个问题是,如果这些对象中的每一个都是彼此独立的,那么我应该或者不应该一次一个地保留每个对象,而不是一次性保留它们或者批量处理它们。如果有5000个记录,那么在调用save / update / insert时,应用程序看起来似乎变慢了,因为它仍然在Hibernate Session中的内存中完成所有操作。但是,如果我改为保存/更新/插入每条记录(一次处理一个ID),然后在完成该对象之前提交,然后再转到下一条记录,它似乎加速了很多。另外,如果我批量处理,比如每200个,或者甚至一次完成5000个,如果一个记录无法插入/更新并且出错,那么任何东西都不会被持久化并且一切都会回滚。

处理此类事情的最佳做法是什么?看起来像是非常普遍的东西。感谢

2 个答案:

答案 0 :(得分:0)

首先,Spring / Hibernate并不是真正用于批处理的。相反,请查看TalendPentaho(如果您使用的是开源代码),或任何大型(大量!)各种商业工具。这些工具中的任何一个都可用于自动生成一堆Java代码,这些代码将完全满足您的需求(包括插入优化,优雅的错误处理等)。

好吧,我们假设你真的,真的想让Spring / Hibernate做批量处理。您有几个不同的问题 - 首先,Hibernate会话生命周期意味着加载的对象希望与实时会话相关联。您可以使用会话flush()强制更改传播到数据库。会话关闭()将擦除所有内容。已经加载的对象只能很难重新连接到新会话(通常更容易重新加载对象)。如果你没有关闭()/ flush()你的会话,最终你(可能)会耗尽内存。您可以通过添加Hibernate二级缓存来解决这个问题......但这只会使事情变得更加复杂并降低速度。

没有任何理由不在独立的Hibernate会话中进行每次插入(打开,执行,关闭)。它不会像专用工具那么快,但它很简单,工作正常,并且或多或少都和你一样好。

答案 1 :(得分:0)

关于批处理要求,请使用Spring批处理link 这提供了所需的所有必要的配料设施。

关于对象加载问题,

  

所以这可能不是   最优的是 - 批次类   只需调用服务即可加载所有内容   这些对象的ID(长值) -   我们将此ID传递给服务   将加载该对象的方法   从DB中通过ID然后再做   处理它。

似乎是正确的。