天天看點

第14 章批量處理(Batch processing)

使用Hibernate将 100 000 條記錄插入到資料庫的一個很自然的做法可能是這樣的

Session session = sessionFactory.openSession();

Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {

   Customer customer = newCustomer(.....);

   session.save(customer);

}

tx.commit();

session.close();

這段程式大概運作到 50 000 條記錄左右會失敗并抛出 記憶體溢出異常(OutOfMemoryException) 。 這是因為 Hibernate 把所有新插入的 客戶(Customer)執行個體在 session級别的緩存區進行了緩存的緣故。

我們會在本章告訴你如何避免此類問題。首先,如果你要執行批量處理并且想要達到一個理想的性能,那麼使用JDBC的批量(batching)功能是至關重要。将JDBC的批量抓取數量(batch size)參數設定到一個合适值 (比如,10-50之間):

hibernate.jdbc.batch_size 20

你也可能想在執行批量處理時關閉二級緩存:

hibernate.cache.use_second_level_cache false

14.1. 批量插入(Batch inserts)

如果要将很多對象持久化,你必須通過經常的調用flush()以及稍後調用 clear()來控制第一級緩存的大小。

   if ( i % 20 == 0 ) { //20, sameas the JDBC batch size //20,與JDBC批量設定相同

       //flush a batch of insertsand release memory:

       //将本批插入的對象立即寫入資料庫并釋放記憶體

       session.flush();

       session.clear();

   }

14.2. 批量更新(Batch updates)

此方法同樣适用于檢索和更新資料。此外,在進行會傳回很多行資料的查詢時,你需要使用 scroll()方法以便充分利用伺服器端遊标所帶來的好處。

ScrollableResults customers =session.getNamedQuery("GetCustomers")

   .setCacheMode(CacheMode.IGNORE)

  .scroll(ScrollMode.FORWARD_ONLY);

int count=0;

while ( customers.next() ) {

   Customer customer = (Customer)customers.get(0);

   customer.updateStuff(...);

   if ( ++count % 20 == 0 ) {

       //flush a batch of updatesand release memory:

14.3. 大批量更新/删除(Bulkupdate/delete)

就像已經讨論的那樣,自動和透明的對象/關系 映射(object/relational mapping)關注于管理對象的狀态。這就意味着對象的狀态存在于記憶體,是以直接更新或者删除 (使用 SQL 語句UPDATE和 DELETE) 資料庫中的資料将不會影響記憶體中的對象狀态和對象資料。 不過,Hibernate提供通過Hibernate查詢語言(第15 章HQL: Hibernate查詢語言)來執行大批 量SQL風格的(UPDATE)和(DELETE) 語句的方法。

UPDATE和 DELETE語句的文法為: ( UPDATE | DELETE )FROM? ClassName (WHERE WHERE_CONDITIONS)?。 有幾點說明:

·在FROM子句(from-clause)中,FROM關鍵字是可選的

·在FROM子句(from-clause)中隻能有一個類名,并且它不能有别名

·不能在大批量HQL語句中使用連接配接(顯式或者隐式的都不行)。不過在WHERE子句中可以使用子查詢。

·整個WHERE子句是可選的。

舉個例子,使用Query.executeUpdate()方法執行一個HQL UPDATE語句:

       Transaction tx =session.beginTransaction();

       String hqlUpdate ="update Customer set name = :newName where name = :oldName";

       int updatedEntities =s.createQuery( hqlUpdate )

                          .setString( "newName", newName )

                          .setString( "oldName", oldName )

                          .executeUpdate();

       tx.commit();

       session.close();

執行一個HQL DELETE,同樣使用 Query.executeUpdate()方法 (此方法是為那些熟悉JDBC PreparedStatement.executeUpdate()的人們而設定的)

       String hqlDelete ="delete Customer where name = :oldName";

       int deletedEntities =s.createQuery( hqlDelete )

                           .executeUpdate();

由Query.executeUpdate()方法傳回的整型值表明了受此操作影響的記錄數量。注意這個數值可能與資料庫中被(最後一條SQL語句)影響了的“行”數有關,也可能沒有。一個大批量HQL操作可能導緻多條實際的SQL語句被執行, 舉個例子,對joined-subclass映射方式的類進行的此類操作。這個傳回值代表了實際被語句影響了的記錄數量。在那個joined-subclass的例子中, 對一個子類的删除實際上可能不僅僅會删除子類映射到的表而且會影響“根”表,還有可能影響與之有繼承關系的joined-subclass映射方式的子類的表。

注意,上述大批量HQL操作的少數限制會在新版本中得到改進;進一步詳細資訊請參考JIRA裡的路線圖(roadmap)。

第13 章攔截器與事件(Interceptors and events)  

起始頁

第15 章HQL: Hibernate查詢語言

來自:http://docs.huihoo.com/hibernate/reference-v3_zh-cn/batch.html

繼續閱讀