hibernate完全以物件導向的方式來運算元據庫,當程式裡以物件導向的方式操作持久化物件時,將被自動轉換為對資料庫的操作。例如呼叫session的delete()方法來刪除持久化物件,hibernate將負責刪除對應的資料記錄;當執行持久化物件的set方法時,hibernate將自動轉換為對應的update方法,修改資料庫的對應記錄。
問題是如果需要同時更新100 000條記錄,是不是要逐一載入100 000條記錄,然後依次呼叫set方法——這樣不僅繁瑣,資料訪問的效能也十分糟糕。對這種批量處理的場景,hibernate提供了批量處理的解決方案,下面分別從批量插入、批量更新和批量刪除3個方面介紹如何面對這種批量處理的情形。
如果需要將100 000條記錄插入資料庫,通常hibernate可能會採用如下做法:
session session = sessionfactory.opensession();
transaction tx = session.begintransaction();
for ( int i=0; i<100000; i++ )
tx.commit();
session.close();
但隨著這個程式的執行,總會在某個時候執行失敗,並且丟擲outofmemoryexception(記憶體溢位異常)。這是因為hibernate的session持有乙個必選的一級快取,所有的user例項都將在session級別的快取區進行了快取的緣故。
為了解決這個問題,有個非常簡單的思路:定時將session快取的資料重新整理入資料庫,而不是一直在session級別快取。可以考慮設計乙個累加器,每儲存乙個user例項,累加器增加1。根據累加器的值決定是否需要將session快取中的資料刷入資料庫。
下面是增加100 000個user例項的**片段:
private void testuser()throws exception
}//提交事務
tx.commit();
//關閉事務
hibernateutil.closesession();
}上面**中,當i%20 == 0時,手動將session處的快取資料寫入資料庫,並手動提交事務。如果不提交事務,資料將依然快取在事務處——未進入資料庫,也將引起記憶體溢位的異常。
這是對session級別快取的處理,還應該通過如下配置來關閉sessionfactory的二級 快取。
hibernate.cache.use_second_level_cache false
注意:除了要手動清空session級別的快取外,最好關閉sessionfactory級別的二級快取。否則,即使手動清空session級別的快取,但因為在sessionfactory級別還有快取,也可能引發異常。
上面介紹的方法同樣適用於批量更新資料,如果需要返回多行資料,可以使用scroll()方法,從而可充分利用伺服器端游標所帶來的效能優勢。下面是進行批量更新的**片段:
private void testuser()throws exception
}tx.commit();
hibernateutil.closesession();
}通過這種方式,雖然可以執行批量更新,但效果非常不好。執行效率不高,而且需要先執行資料查詢,然後再執行資料更新,並且這種更新將是逐行更新,即每更新一行記錄,都需要執行一條update語句,效能非常低下。
為了避免這種情況,hibernate提供了一種類似於sql的批量更新和批量刪除的hql語法。
hibernate提供的hql語句也支援批量的update和delete語法。
批量update和delete語句的語法格式如下:
update | delete from? classname [where where_conditions]
關於上面的語法格式有以下四點值得注意:
● 在from子句中,from關鍵字是可選的。即完全可以不寫from關鍵字。
● 在from子句中只能有乙個類名,該類名不能有別名。
● 不能在批量hql語句中使用連線,顯式的或隱式的都不行。但可以在where子句中使用子查詢。
● 整個where子句是可選的。
假設,需要批量更改user類例項的name屬性,可以採用如下**片段完成:
private void testuser()throws exception
從上面**中可以看出,這種語法非常類似於preparedstatement的executeupdate語法。實際上,hql的這種批量更新就是直接借鑑了sql語法的update語句。
注意:使用這種批量更新語法時,通常只需要執行一次sql的update語句,就可以完成所有滿足條件記錄的更新。但也可能需要執行多條update語句,這是因為有繼承對映等特殊情況,例如有乙個person例項,它有customer的子類例項。當批量更新person例項時,也需要更新customer例項。如果採用joined-subclass或union-subclass對映策略,person和customer例項儲存在不同的表中,因此可能需要多條update語句。
執行乙個hql delete,同樣使用 query.executeupdate() 方法,下面是一次刪除上面全部記錄的**片段:
private void testuser()throws exception
由query.executeupdate()方法返回乙個整型值,該值是受此操作影響的記錄數量。實際上,hibernate的底層操作是通過jdbc完成的。因此,如果有批量的update或delete操作被轉換成多條update或delete語句,該方法返回的是最後一條sql語句影響的記錄行數。
**
Hibernate 批量更新資料
進行批量更新時,如果一下子把所有物件載入到session的快取中,然後再進快取中一一更新它們,顯然是不可取的,為了解決這一問題,可以使用滾動的結果集 org.hibernate.scrollableresults,query的 scroll 方法返回乙個scrollableresults物件。以下是...
Hibernate入門 批量插入資料
一般如果要插入100萬條資料,則會寫如下 package org.xiazdong.test import junit.framework.testcase import org.hibernate.session import org.hibernate.sessionfactory import...
mysql批量插入資料 MySQL中批量插入資料
例1 方法一 sql語句操作 delimiter 以delimiter來標記用 表示儲存過程結束 create procedure pre 建立pre 儲存方法 begin declare i int 定義i變數 set i 2 while i 53 do insert into lineinfo ...