hibernate處理批次更新和大量刪除__Hibernate
來源:互聯網
上載者:User
9.4 批量處理資料通常,在一個Session對象的緩衝中只存放數量有限的持久化對象,等到Session對象處理事務完畢,還要關閉Session對象,從而及時釋放Session的緩衝佔用的記憶體。批量處理資料是指在一個事務中處理大量資料。以下程式在一個事務中批次更新CUSTOMERS表中年齡大於零的所有記錄的AGE欄位:Transaction tx = session.beginTransaction();Iterator customers=session.createQuery("from Customer c where c.age>0").list().iterator();while(customers.hasNext()){Customer customer=(Customer)customers.next();customer.setAge(customer.getAge()+1);}tx.commit();session.close();如果CUSTOMERS表中有1萬條年齡大於零的記錄,那麼Hibernate會一下子載入1萬個Customer對象到記憶體。當執行tx.commit()方法時,會清理緩衝,Hibernate執行1萬條更新CUSTOMERS表的update語句:update CUSTOMERS set AGE=? …. where ID=i;update CUSTOMERS set AGE=? …. where ID=j;……update CUSTOMERS set AGE=? …. where ID=k;以上批次更新方式有兩個缺點:佔用大量記憶體,必須把1萬個Customer對象先載入到記憶體,然後一一更新它們。執行的update語句的數目太多,每個update語句只能更新一個Customer對象,必須通過1萬條update語句才能更新1萬個Customer對象,頻繁地訪問資料庫,會大大降低應用的效能。一般說來,應該儘可能避免在應用程式層進行大量操作,而應該在資料庫層直接進行大量操作,例如直接在資料庫中執行用於批次更新或刪除的SQL語句,如果大量操作的邏輯比較複雜,則可以通過直接在資料庫中啟動並執行預存程序來完成大量操作。並不是所有的資料庫系統都支援預存程序。例如目前的MySQL就不支援預存程序,因此不能通過預存程序來進行批次更新或大量刪除。當然,在應用程式層也可以進行大量操作,主要有以下方式:(1)通過Session來進行大量操作。(2)通過StatelessSession來進行大量操作。(3)通過HQL來進行大量操作。(4)直接通過JDBC API來進行大量操作。9.4.1 通過Session來進行大量操作Session的save()以及update()方法都會把處理的對象存放在自己的緩衝中。如果通過一個Session對象來處理大量持久化對象,應該及時從緩衝中清空已經處理完畢並且不會再訪問的對象。具體的做法是在處理完一個對象或小批量對象後,立刻調用flush()方法清理緩衝,然後再調用clear()方法清空緩衝。通過Session來進行大量操作會受到以下約束:(1)需要在Hibernate的設定檔中設定JDBC單次批量處理的數目,合理的取值通常為10到50之間,例如:hibernate.jdbc.batch_size=20在按照本節介紹的方法進行大量操作時,應該保證每次向資料庫發送的批量SQL語句數目與這個batch_size屬性一致。(2)如果對象採用"identity"標識符產生器,則Hibernate無法在JDBC層進行批量插入操作。(3)進行大量操作時,建議關閉Hibernate的第二級緩衝。本書的姊妹篇《精通Hibernate:進階篇》對第二級緩衝做了詳細介紹。Session的緩衝為Hibernate的第一級緩衝,通常它是事務範圍內的緩衝,也就是說,每個事務都有單獨的第一級緩衝。SessionFactory的外置緩衝為Hibernate的第二級緩衝,它是應用範圍內的緩衝,也就是說,所有事務都共用同一個第二級緩衝。在任何情況下,Hibernate的第一級緩衝總是可用的。而預設情況下,Hibernate的第二級緩衝是關閉的,此外也可以在Hibernate的設定檔中通過如下方式顯式關閉第二級緩衝:hibernate.cache.use_second_level_cache=false1.批量插入資料以下代碼一共向資料庫中插入十萬條CUSTOMERS記錄,單次批量插入20條CUSTOMERS記錄:Session session = sessionFactory.openSession();Transaction tx = session.beginTransaction();for ( int i=0; i<100000 i="" customer="" customer="new" customer="" session="" save="" customer="" if="" i="" 20="=" 0="" 20="" session="" flush="" 20="" sql="" insert="" session="" clear="" customer="" tx="" commit="" session="" close="" session="" flush="" 20="" session="" clear="" 20="" customer="" hibernate="" hibernate="" jdbc="" batch_size="" 20="" session="" customer="" customer="" identity="" 2="" session="" org="" hibernate="" scrollableresults="" query="" scroll="" scrollableresults="" customer="" scrollableresults="" customer="" session="" session="sessionFactory.openSession();" transaction="" tx="session.beginTransaction();" scrollableresults="" customers="session.createQuery('from" customer="" scroll="" scrollmode="" forward_only="" int="" count="0;" while="" customers="" next="" customer="" customer="(Customer)" customers="" get="" 0="" customer="" setage="" customer="" getage="" 1="" customer="" age="" if="" count="" 20="=" 0="" 20="" session="" flush="" 20="" sql="" update="" session="" clear="" customer="" tx="" commit="" session="" close="" query="" scroll="" scrollableresults="" customer="" customers="" scrollableresults="" customer="" hibernate="" hibernate="" jdbc="" batch_size="" 20="" scrollableresults="" customers="session.createQuery('from" customer="" setcachemode="" cachemode="" ignore="" scroll="" scrollmode="" forward_only="" 9="" 4="" 2="" statelesssession="" session="" session="" session="" statelesssession="" statelesssession="" statelesssession="" session="sessionFactory.openStatelessSession();" transaction="" tx="session.beginTransaction();" scrollableresults="" customers="session.getNamedQuery('GetCustomers')" scroll="" scrollmode="" forward_only="" while="" customers="" next="" customer="" customer="(Customer)" customers="" get="" 0="" customer="" setage="" customer="" getage="" 1="" customer="" age="" session="" update="" customer="" update="" customers="" tx="" commit="" session="" close="" statelesssession="" session="" statelesssession="" session="" 1="" statelesssession="" statelesssession="" 2="" statelesssession="" hibernate="" 3="" statelesssession="" save="" update="" delete="" sql="" sql="" 4="" statelesssession="" customer="" statelesssession="" update="" 5="" statelesssession="" statelesssession="" customer="" order="" 6="" statelesssession="" interceptor="" hibernate="" 7="" statelesssession="" oid="" 1="" customer="" customer="" statelesssession="" session="sessionFactory.openStatelessSession();" customer="" c1="(Customer)session.get(Customer.class,new" long="" 1="" customer="" c2="(Customer)session.get(Customer.class,new" long="" 1="" system="" out="" println="" c1="=c2);" false="" 9="" 4="" 3="" hql="" hibernate3="" hql="" hibernate="" query="" language="" hibernate="" session="" query="" executeupdate="" jdbc="" api="" preparedstatement="" executeupdate="" hql="" sql="" 1="" hql="" customer="" session="" session="sessionFactory.openSession();" transaction="" tx="session.beginTransaction();" string="" hqlupdate="update Customer c set c.name = :newName where c.name = :oldName" int="" updatedentities="session.createQuery(" hqlupdate="" setstring="" newname="" mike="" setstring="" oldname="" tom="" executeupdate="" tx="" commit="" session="" close="" sql="" update="" customers="" set="" name="Mike" where="" name="Tom" 2="" session="" delete="" hql="" customer="" session="" session="sessionFactory.openSession();" transaction="" tx="session.beginTransaction();" string="" hqldelete="delete Customer c where c.name = :oldName" int="" deletedentities="session.createQuery(" hqldelete="" setstring="" oldname="" tom="" executeupdate="" tx="" commit="" session="" close="" sql="" delete="" from="" customers="" where="" name="Tom" 3="" hql="" insert="" into="" entityname="" properties_list="" select_statement="" entityname="" properties_list="" select_statement="" hql="" insert="" into="" select="" insert="" into="" values="" hql="" delinquentaccount="" customer="" id="" name="" delinquent_accounts="" customers="" delinquentaccount="" hbm="" xml="" customer="" hbm="" xml="" customers="" delinquent_accounts="" session="" session="sessionFactory.openSession();" transaction="" tx="session.beginTransaction();" string="" hqlinsert="insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where c.id>1" int="" createdentities="s.createQuery(" hqlinsert="" executeupdate="" tx="" commit="" session="" close="" sql="" insert="" into="" delinquent_accounts="" id="" name="" select="" id="" name="" from="" customers="" where="" id="">19.4.4 直接通過JDBC API來進行大量操作當通過JDBC API來執行SQL insert、update和delete語句時,SQL語句中涉及到的資料不會被載入到記憶體中,因此不會佔用記憶體空間。以下程式直接通過JDBC API來執行用於批次更新的SQL語句:Transaction tx = session.beginTransaction();//獲得該Session使用的資料庫連接java.sql.Connection con=session.connection();//通過JDBC API執行用於批次更新的SQL語句PreparedStatement stmt=con.prepareStatement("update CUSTOMERS set AGE=AGE+1 "+"where AGE>0 ");stmt.executeUpdate();tx.commit();以上程式通過Session的connection()方法獲得該Session使用的資料庫連接,然後通過它建立PreparedStatement對象並執行SQL語句。值得注意的是,應用程式仍然通過Hibernate的Transaction介面來聲明事務邊界。值得注意的是,在Hibernate3中,儘管Session的connection()方法還存在,但是已經被廢棄,不提倡使用了,不過Hibernate3提供了替代方案:org.hibernate.jdbc.Work介面表示直接通過JDBC API來訪問資料庫的操作,Work介面的execute()方法用於執行直接通過JDBC API來訪問資料庫的操作:public interface Work {//直接通過JDBC API來訪問資料庫的操作public void execute(Connection connection) throws SQLException;}Session的doWork(Work work)方法用於執行Work對象指定的操作,即調用Work對象的execute()方法。Session會把當前使用的資料庫連接傳給execute()方法。以下程式示範了通過Work介面以及Session的doWork()方法來執行大量操作的過程:Transaction tx=session.beginTransaction();//定義一個匿名類,實現了Work介面Work work=new Work(){public void execute(Connection connection)throws SQLException{//通過JDBC API執行用於批次更新的SQL語句PreparedStatement stmt=connection.prepareStatement("update CUSTOMERS set AGE=AGE+1 "+"where AGE>0 ");stmt.executeUpdate();}};//執行worksession.doWork(work);tx.commit();當通過JDBC API中的PreparedStatement介面來執行SQL語句時,SQL語句中涉及到的資料不會被載入到Session的緩衝中,因此不會佔用記憶體空間。