Hibernate批量处理及缓存机制

使用 Hibernate 将 100,000 条记录插入到数据库的一个很天真的做法可能是这样的:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
      Customer customer = new Customer(.....);
      session.save(customer);
}
tx.commit();
session.close();

这段程序大概运行到 50,000 条记录左右会失败并抛出内存溢(OutOfMemoryException)。
这是因为 Hibernate 把所有新插入的客户(Customer)实例在 session 级别的缓存区进行了缓存的缘故。
先说下hibernate缓存机制,优先session,而后sessionfatory(二级缓存),而后去数据库中查找,具体如下:

if(session开启){
	hibernate生成sql;
	去session执行sql;
	if(session中有){
	   获得session结果集;
    }else{
        去SessionFactory中查找;
        if(二级缓存关闭或查不到) {
           发送sql去数据库中查;
           获得数据库结果集;
        }else{
          获得sessionFactory结果集;
        }
    }
}else{
  发送sql去数据库中查;
  获得数据库结果集;
}

Hibernate缓存配置:
jar包:hibernate-ehcache

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>4.0.0.Final</version>
		</dependency>

hibernate配置

<!-- 二级缓存: 开启   提供类  缓存配置xml位置-->
		<property name="cache.use_second_level_cache">true</property>
        <property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
        <property name="cache.provider_configuration_file_resource_path">hbm.ehcache.hbm.xml</property>

映射配置:

 <cache usage="read-only"/><!-- 开启二级缓存:只读 -->

缓存策略:
只读 read-only
非严格读/写 nonstrict-read-write
读写 read-write
事务缓存 transactional

批量插入(Batch inserts)
如果要将很多对象持久化,你必须通过经常的调用 flush() 以及稍后调用 clear() 来控制第一级
缓存的大小

@Test
	public void Test12() {
		Configuration cfg = new Configuration().configure();//获取配置
		SessionFactory sessionFactory = cfg.buildSessionFactory();//创建会话工厂
		Session session = sessionFactory.openSession();//开启会话
		Transaction transaction = session.beginTransaction();//开启事务
			for(int i = 1;i<=25;i++) {
				Dept dept = new Dept();
				dept.setDname("gz"+i);
				session.save(dept);
				if(i%10 == 0) {
					session.flush();//
					session.clear();
				}
			}
			transaction.commit();
		}catch(Exception e) {
			e.printStackTrace();
			transaction.rollback();//事务异常则回滚
		}finally{//关闭资源
			session.close();
			sessionFactory.close();
		}
	}

执行结果:

Hibernate: 
    select
        hibernate_sequence.nextval 
    from
        dual
        //10遍
Hibernate: 
    insert 
    into
        dept1
        (dname, loc, deptno) 
    values
        (?, ?, ?)//10遍
Hibernate: 
    select
        hibernate_sequence.nextval 
    from
        dual
        //10遍
Hibernate: 
    insert 
    into
        dept1
        (dname, loc, deptno) 
    values
        (?, ?, ?)//10遍
Hibernate: 
    select
        hibernate_sequence.nextval 
    from
        dual
        //5遍
Hibernate: 
    insert 
    into
        dept1
        (dname, loc, deptno) 
    values
        (?, ?, ?)//5遍

批量更新:

ScrollableResults depts = session.getNamedQuery("getDepts")
				.setCacheMode(CacheMode.IGNORE)
				.scroll(ScrollMode.FORWARD_ONLY);
int i = 0;
while (depts.next()) {
		Dept dept = (Dept) depts.get(0);
		dept.setDname("gz3");
		if(++i%5 == 0) {
			session.flush();
			session.clear();
		}
}
transaction.commit();

分页查询:

Query query =  session.createQuery("from Dept");
			query.setMaxResults(5);
			query.setFirstResult(3);
			List<Dept> list = query.list();
			for(Dept d:list) {
				System.out.println(d.getDeptno());
			}
transaction.commit();//提交事务

发送的sql:

Hibernate: 
    select
        * 
    from
        ( select
            row_.*,
            rownum rownum_ 
        from
            ( select
                dept0_.deptno as deptno0_,
                dept0_.dname as dname0_,
                dept0_.loc as loc0_ 
            from
                dept1 dept0_ ) row_ 
        where
            rownum <= ?
        ) 
    where
        rownum_ > ?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章