Hibernate讀書筆記—–hibernate的批量處理 – JAVA編程語言程序開發技術文章

    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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *