hibernate之大批量和批量操作(利用批量处理)
想像你必须操作所有的Item对象,并且必须做的改变不像设置标记这么繁琐。也假设你无法创建SQL存储过程,不管出于什么原因。你唯一的选择是在Java中编写这个过程,并把大量的数据获取到内存,通过这个过程来运行它。你应该通过把工作批量化来执行这个过程。这意味着创建许多更小的数据集,代替不适合内存的单个数据集。
----------
1.利用批量更新编写过程
下列代码同时加载了100个Item对象用于处理:
你用(简单的)HQL查询从数据库中加载所有的Item对象。但不是完全把查询的结果获取到内存,而是打开了一个在线的游标。游标是一个指针,指向处在数据库中的结果集。可以通过ScrollableResults对象控制游标,并让它随着结果移动。get(int i)调用把单个对象获取到内存中,即游标当前所指的对象。对next()的每一次调用,都使游标朝着下一个对象前进。为了避免内存耗尽,你在下一个100个对象加载到内存中之前,flush()和clear()一次持久化上下文。
持久化上下文的清除把你对最新的100个Item对象所做的改变都写到数据库中。为了实现最好的性能,你应该把hibernate(和JDBC)配置属性hibernate.jdbc.batch_size的大小设置为与过程批量的大小相同:100;然后在清除期间执行的所有UPDATE语句也都在JDBC级被批量化。(注意,你应该给任何批量操作禁用二级高速缓存;否则,批量过程期间对象的每一次修改都必须为这个持久化类传播到二级高速缓存。这是一项没有必要的过载。)
----------
2.指量插入许多对象
如果必须在一个工作单元中创建几百或者几千个对象,就可能遇到内存耗尽的问题。被传递到save()或者persist()的每一个对象都被添加到这个持久化上下文高速缓存中。
一种简单的解决方案是,在一定数量的对象之后清除持久化上下文。你有效地批量插入:
这里同时创建并持久化了100000个对象,每次100个对象。还是要记住把hibernate.jdbc.batch_size配置属性设置为一个相等的值,并给持久化类禁用二级高速缓存。
警告:如果你的实体通过identity标识符生成器被映射,hibernate就会悄悄地禁用JDBC批量插入;许多JDBC驱动程序在这种情况下都不支持批量。