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_ > ?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章