Hibernate完全以面向對象的方式來操作數據庫,當程序裡以面向對象的方式操作持久化對象,將被自動轉換為對數據庫的操作。但存在這樣一個問題,如果我們想同時更新100000條記錄,是不是要逐一加載100000條記錄,然後依次調用setter方法。采用這種方法實在是太繁瑣瞭,而且嚴重影響瞭數據的訪問性能。Hibernate提供的批量處理的方案來解決這個問題。
一、批量插入
如果我們需要插入100000條記錄,通過hibernate可能會采用如下的方式處理:
[java]
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
for (int i = 0; i < 100000; i++) {
User user = new User();
user.setName("userName"+i);
user.setAge(i);
session.save(session);
}
tx.commit();
session.close();
但是這個程序存在一個問題:當程序運行到某個地方,總是會拋出OutOfMemoryException內存溢出異常。這是因為Hibernate的Session持有一個必選的一級緩存,所有的User實例都會Session級別的緩存區進行緩存的緣故。
如果你要執行批量處理並且想要達到一個理想的性能,那麼使用JDBC的批量(batching)功能是至關重要。將JDBC的批量抓取數量(batch size)參數設置到一個合適值。
[html] view plaincopyprint?
<property name="jdbc.batch_size">20</property>
可能也會想到關閉二級緩存:
[html] view plaincopyprint?
hibernate.cache.use_second_level_cache false
但這個並不是必須的。
解決這個問題的方案就是:定時的將session的緩存數據刷入數據庫,同時通過調用 clear() 來控制一級緩存的大小。如下:
[java]
static void addUser() throws Exception{
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//循環1000次,插入1000條記錄
for(int i = 0;i < 100000;i++){
//創建User對象
User user = new User();
user.setName("userName"+i);
user.setAge(i);
//在session級別緩存User實例
session.save(user);
//每當累加器是20的倍數的時候,將session中數據刷入數據庫,並且情況session緩存
if(i%20==0){
session.flush();
session.clear();
}
}
<span style="font-size:16px;"></span>
二、批量更新
上面介紹的方法同樣也適用於批量更新。在進行會返回很多行數據的查詢時, 你需要使用 scroll() 方法以便充分利用服務器端遊標所帶來的好處。
[java]
static void updateUser() throws Exception {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//查詢出User表中所有的記錄
ScrollableResults re = session.createQuery("from User").setCacheMode(CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
int count = 1;
while(re.next()){
User user = (User) re.get(0);
//當count=20的倍數時,將更新的結果從session中flush到數據庫
user.setName("新用戶:"+count);
if(++count%20==0){
session.flush();
session.clear();
}
}
tx.commit();
session.close();
}
通過這種方式,雖然可以進行批量更新,但由於它需要先執行數據查詢,然後才能執行數據更新,所以執行效率不高。為瞭避免這種情況,我們可以使用DML風格進行數據的批量更新。
三、DML風格的批量更新/刪除
Hibernate提供通過Hibernate查詢語言(HQL)來執行大批量SQL風格的DML語句的方法。
批量update、delete語句的語法格式如下:( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)。
這裡需要註意如下幾點:
1、在FROM子句中,FROM關鍵字是可選的。
2、在FROM子句(from-clause)中隻能有一個實體名,它可以是別名。如果實體名是別名,那麼任何被引用的屬性都必須加上此別名的前綴;如果不是別名,那麼任何有前綴的屬性引用都是非法的。
3、不能在批量HQL語句中使用連接,顯式或者隱式的都不行。不過在WHERE子句中可以使用子查詢。可以在where子句中使用子查詢,子查詢本身可以包含join。
4、整個WHERE子句是可選的。
實例:使用Query.executeUpdate()方法執行一個HQL UPDATE語句
[java]
static void updateUser() throws Exception{
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//定義批量更新的HQL語句 www.aiwalls.com
String hql = "update User as user set user.name = :name";
//執行更新
session.createQuery(hql).setString("name", "name").executeUpdate();
tx.commit();
session.close();
}
使用這種批量更新語法時,通常隻需要執行一次SQL的update語句,就可以完成所有滿足條件記錄的更新。但也有可能需要執行多條update語句,這是因為有繼承映射等情況。
執行一個HQL DELETE,同樣使用 Query.executeUpdate() 方法:
[java]
//使用DML風格的批量刪除
static void deleteUser() throws Exception{
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
//定義批量更新的HQL語句
String hql = "delete User";
//執行刪除
session.createQuery(hql).executeUpdate();
tx.commit();
session.close();
}
Query.executeUpdate()方法返回一個整型值,該值是受此操作影響的記錄數量。
作者:chenssy