使用 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_ > ?