Hibernate批量处理
(一) 认识批量处理
代码
Session session=sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for(int i=0;i<100000;i++){
Customer customer = new Customer(...);
session.save(customer);
}
tx.commit();
session.close();
运行的现象:
大概在50000条数据的时候,程序会出现异常,内存溢出异常OutOfMemoryException
原因:
Hibernate把所有的新插入的客户实例在session级别的缓存区进行缓存的缘故。
解决方案:
- 批量抓取
- hibernate.jdbc.batch_size 20
- 关闭二级缓存
- hibernate.cache.use_second_level_cache flase
(二) 批量插入
合理的方案:
如果要将很多对象持久化,必须经常调用flush()以及稍后调用clear()来控制一级缓存的大小。
代码演示
public class UserManager
{
public staitc void main(String []args){
UserManager userManager = new UserManager();
userManager.addUsers();
HibernateUtil.sessionFactory.close();
}
public void addUsers() throws Exception{{
Session session = HiernateUtil.currentSession();
Transaction transaction = session.beginTransaction();
//循环100000次,插入100000条记录
for(int i=0;i<100000;i++){
User user = new User();
user.setName....
session.save(user);
//每当累加器是20的倍数的时候,将session中的数据刷入到数据库中
if(i%20 == 0){
session.flush();
session.clear();
}
}
transaction.close();
HibernateUtil.closeSession();
}
}
注意不但需要处理session的缓存,还需要关闭sessionFactory的二级缓存。
(三) 批量更新
在进行会返回多行数据的查询的时候,需要使用方法scroll()利用服务器游标所带来的的好处。
代码演示
Sessionsession = sessionFactory.openSession();
Transaction transaction = sessionFactory.beginTransaction();
ScrollableResults customers = session.getNameQuery("GetCustomers").setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
while(customers.next()){
Customer customer = (Customer)customers.get(0);
customer.updateStuff(...);
if(count++ == 0){
//flush a batch of updates and relase memory
session.flush();
session.clear();
}
}
缺点:
这种方式执行更新效率不高,hibernate需要查询一条语句然后再更新一条语句,为了避免这种性能低下的情形,Hibernate提供了一种类似于DML语句的批量更新。
(四) StatelessSession(无状态会话)接口
思想:
Hibernatei提供了基于命令的API,可以用detached object的形式把数据以流的方法加入到数据库,或者从数据库中取出
StatelessSession的特点
- 没有持久化的上下文
- 不实现第一级cache也不与第二级缓存交互
- 不实现事务化也不实现脏数据检查
- 通过StatelessSession得到的实例会立即脱管,与任何持久化上下文都没有关系
什么是脏数据?脏数据并不是废弃和无用的数据,而是状态前后发生变化的数据。我们看下面的代码:
Transaction tx=session.beginTransaction();
User user=(User)session.load(User.class,”1”);//从数据库中加载符合条件的数据
user.setName(“zx”);//改变了user对象的姓名属性,此时user对象成为了所谓的“脏数据”
tx.commit();
接口StatelessSession定义的insert,update,delete操作时直接数据库的级别操作,与session有很大的不同。