<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      37 Posts :: 64 Stories :: 21 Comments :: 0 Trackbacks

    Hibernate 完全以面向對象的方式來操作數據庫,當程序里以面向對象的方式操作持久化對象時,將被自動轉換為對數據庫的操作。例如調用Session的 delete()方法來刪除持久化對象,Hibernate將負責刪除對應的數據記錄;當執行持久化對象的set方法時,Hibernate將自動轉換為對應的update方法,修改數據庫的對應記錄。

    問題是如果需要同時更新100?000條記錄,是不是要逐一加載100?000條記錄,然后依次調用set方法——這樣不僅繁瑣,數據訪問的性能也十分糟糕。對這種批量處理的場景,Hibernate提供了批量處理的解決方案,下面分別從批量插入、批量更新和批量刪除3個方面介紹如何面對這種批量處理的情形。

    4.2.1 批量插入

    如果需要將100?000條記錄插入數據庫,通常Hibernate可能會采用如下做法:

    1. Session session = sessionFactory.openSession();   
    2. Transaction tx = session.beginTransaction();   
    3. for ( int i=0; i<100000; i++ ) {   
    4.     User u = new User (.....);   
    5.     session.save(customer);   
    6. }   
    7.   
    8. tx.commit();   
    9. session.close();  
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    for ( int i=0; i<100000; i++ ) {
    User u = new User (.....);
    session.save(customer);
    }
    tx.commit();
    session.close();

    但隨著這個程序的運行,總會在某個時候運行失敗,并且拋出OutOfMemoryException(內存溢出異常)。這是因為Hibernate的Session持有一個必選的一級緩存,所有的User實例都將在Session級別的緩存區進行了緩存的緣故。

    為了解決這個問題,有個非常簡單的思路:定時將Session緩存的數據刷新入數據庫,而不是一直在Session級別緩存。可以考慮設計一個累加器,每保存一個User實例,累加器增加1。根據累加器的值決定是否需要將Session緩存中的數據刷入數據庫。

    下面是增加100?000個User實例的代碼片段:

    1. private void testUser()throws Exception   
    2.   
    3. {   
    4.   
    5.     //打開Session   
    6.   
    7.     Session session = HibernateUtil.currentSession();   
    8.   
    9.     //開始事務   
    10.   
    11.     Transaction tx = session.beginTransaction();   
    12.   
    13.     //循環100 000次,插入100 000條記錄   
    14.   
    15.     for (int i = 0 ; i < 1000000 ; i++ )   
    16.     {   
    17.       //創建User實例   
    18.      User u1 = new User();   
    19.         u1.setName("xxxxx" + i);   
    20.         u1.setAge(i);   
    21.         u1.setNationality("china");   
    22.         //在Session級別緩存User實例   
    23.         session.save(u1);   
    24.         //每當累加器是20的倍數時,將Session中的數據刷入數據庫,并清空Session緩存   
    25.   
    26.         if (i % 20 == 0)   
    27.         {   
    28.   
    29.             session.flush();   
    30.   
    31.             session.clear();   
    32.   
    33.             tx.commit();   
    34.   
    35.             tx = session.beginTransaction();   
    36.         }   
    37.     }   
    38.   
    39.     //提交事務   
    40.     tx.commit();   
    41.       //關閉事務   
    42.     HibernateUtil.closeSession();   
    43. }  
    private void testUser()throws Exception
    {
    //打開Session
    Session session = HibernateUtil.currentSession();
    //開始事務
    Transaction tx = session.beginTransaction();
    //循環100 000次,插入100 000條記錄
    for (int i = 0 ; i < 1000000 ; i++ )
    {
    //創建User實例
    User u1 = new User();
    u1.setName("xxxxx" + i);
    u1.setAge(i);
    u1.setNationality("china");
    //在Session級別緩存User實例
    session.save(u1);
    //每當累加器是20的倍數時,將Session中的數據刷入數據庫,并清空Session緩存
    if (i % 20 == 0)
    {
    session.flush();
    session.clear();
    tx.commit();
    tx = session.beginTransaction();
    }
    }
    //提交事務
    tx.commit();
    //關閉事務
    HibernateUtil.closeSession();
    }
    

    上面代碼中,當i%20 == 0時,手動將Session處的緩存數據寫入數據庫,并手動提交事務。如果不提交事務,數據將依然緩存在事務處——未進入數據庫,也將引起內存溢出的異常。

    這是對Session級別緩存的處理,還應該通過如下配置來關閉SessionFactory的二級      緩存。

    hibernate.cache.use_second_level_cache false

    注意:除了要手動清空Session級別的緩存外,最好關閉SessionFactory級別的二級緩存。否則,即使手動清空Session級別的緩存,但因為在SessionFactory級別還有緩存,也可能引發異常。

    4.2.2 批量更新

    上面介紹的方法同樣適用于批量更新數據,如果需要返回多行數據,可以使用scroll()方法,從而可充分利用服務器端游標所帶來的性能優勢。下面是進行批量更新的代碼片段:

    1. private void testUser()throws Exception   
    2.   
    3. {   
    4.   
    5.     //打開Session   
    6.   
    7.     Session session = HibernateUtil.currentSession();   
    8.   
    9.     //開始事務   
    10.   
    11.     Transaction tx = session.beginTransaction();   
    12.   
    13.     //查詢出User表中的所有記錄   
    14.   
    15.     ScrollableResults users = session.createQuery("from User")   
    16.   
    17.         .setCacheMode(CacheMode.IGNORE)   
    18.   
    19.         .scroll(ScrollMode.FORWARD_ONLY);   
    20.   
    21.     int count=0;   
    22.   
    23.     //遍歷User表中的全部記錄   
    24.   
    25.     while ( users.next() )   
    26.   
    27.     {   
    28.   
    29.         User u = (User) users.get(0);   
    30.   
    31.         u.setName("新用戶名" + count);   
    32.   
    33.         //當count為20的倍數時,將更新的結果從Session中flush到數據庫   
    34.   
    35.         if ( ++count % 20 == 0 )   
    36.   
    37.         {   
    38.   
    39.             session.flush();   
    40.   
    41.             session.clear();   
    42.   
    43.         }   
    44.   
    45.     }   
    46.   
    47.     tx.commit();   
    48.   
    49.     HibernateUtil.closeSession();   
    50.   
    51. }  
    private void testUser()throws Exception
    {
    //打開Session
    Session session = HibernateUtil.currentSession();
    //開始事務
    Transaction tx = session.beginTransaction();
    //查詢出User表中的所有記錄
    ScrollableResults users = session.createQuery("from User")
    .setCacheMode(CacheMode.IGNORE)
    .scroll(ScrollMode.FORWARD_ONLY);
    int count=0;
    //遍歷User表中的全部記錄
    while ( users.next() )
    {
    User u = (User) users.get(0);
    u.setName("新用戶名" + count);
    //當count為20的倍數時,將更新的結果從Session中flush到數據庫
    if ( ++count % 20 == 0 )
    {
    session.flush();
    session.clear();
    }
    }
    tx.commit();
    HibernateUtil.closeSession();
    }
    

    通過這種方式,雖然可以執行批量更新,但效果非常不好。執行效率不高,而且需要先執行數據查詢,然后再執行數據更新,并且這種更新將是逐行更新,即每更新一行記錄,都需要執行一條update語句,性能非常低下。

    為了避免這種情況,Hibernate提供了一種類似于SQL的批量更新和批量刪除的HQL語法。

    4.2.3 SQL風格的批量更新/刪除

    Hibernate提供的HQL語句也支持批量的UPDATE和DELETE語法。

    批量UPDATE和DELETE語句的語法格式如下:

    UPDATE | DELETE FROM? ClassName [WHERE WHERE_CONDITIONS]

    關于上面的語法格式有以下四點值得注意:

       ● 在FROM子句中,FROM關鍵字是可選的。即完全可以不寫FROM關鍵字。

       ● 在FROM子句中只能有一個類名,該類名不能有別名。

       ● 不能在批量HQL語句中使用連接,顯式的或隱式的都不行。但可以在WHERE子句中使用子查詢。

       ● 整個WHERE子句是可選的。

    假設,需要批量更改User類實例的name屬性,可以采用如下代碼片段完成:

    1. private void testUser()throws Exception   
    2.   
    3. {   
    4.   
    5.     //打開Session   
    6.   
    7.     Session session = HibernateUtil.currentSession();   
    8.   
    9.     //開始事務   
    10.   
    11.     Transaction tx = session.beginTransaction();   
    12.   
    13.     //定義批量更新的HQL語句   
    14.   
    15.     String hqlUpdate = "update User set name = :newName";   
    16.   
    17.     //執行更新   
    18.   
    19.     int updatedEntities = session.createQuery( hqlUpdate )   
    20.   
    21.                            .setString( "newName", "新名字" )   
    22.   
    23.                            .executeUpdate();   
    24.   
    25.     //提交事務   
    26.   
    27.     tx.commit();   
    28.   
    29.     HibernateUtil.closeSession();   
    30.   
    31. }  
    private void testUser()throws Exception
    {
    //打開Session
    Session session = HibernateUtil.currentSession();
    //開始事務
    Transaction tx = session.beginTransaction();
    //定義批量更新的HQL語句
    String hqlUpdate = "update User set name = :newName";
    //執行更新
    int updatedEntities = session.createQuery( hqlUpdate )
    .setString( "newName", "新名字" )
    .executeUpdate();
    //提交事務
    tx.commit();
    HibernateUtil.closeSession();
    }
    

    從上面代碼中可以看出,這種語法非常類似于PreparedStatement的executeUpdate語法。實際上,HQL的這種批量更新就是直接借鑒了SQL語法的UPDATE語句。

    注意:使用這種批量更新語法時,通常只需要執行一次SQL的UPDATE語句,就可以完成所有滿足條件記錄的更新。但也可能需要執行多條UPDATE語句,這是因為有繼承映射等特殊情況,例如有一個Person實例,它有Customer的子類實例。當批量更新Person實例時,也需要更新Customer實例。如果采用joined-subclass或union-subclass映射策略,Person和Customer實例保存在不同的表中,因此可能需要多條UPDATE語句。

    執行一個HQL DELETE,同樣使用 Query.executeUpdate() 方法,下面是一次刪除上面全部記錄的代碼片段:

    1. private void testUser()throws Exception   
    2.   
    3. {   
    4.   
    5.     //打開Session實例   
    6.   
    7.     Session session = HibernateUtil.currentSession();   
    8.   
    9.     //開始事務   
    10.   
    11.     Transaction tx = session.beginTransaction();   
    12.   
    13.     //定義批量刪除的HQL語句   
    14.   
    15.     String hqlUpdate = "delete User";   
    16.   
    17.     //執行批量刪除   
    18.   
    19.     int updatedEntities = session.createQuery( hqlUpdate )   
    20.   
    21.                            .executeUpdate();   
    22.   
    23.     //提交事務   
    24.   
    25.     tx.commit();   
    26.   
    27.     //關閉Session   
    28.   
    29.     HibernateUtil.closeSession();   
    30.   
    31. }  
    private void testUser()throws Exception
    {
    //打開Session實例
    Session session = HibernateUtil.currentSession();
    //開始事務
    Transaction tx = session.beginTransaction();
    //定義批量刪除的HQL語句
    String hqlUpdate = "delete User";
    //執行批量刪除
    int updatedEntities = session.createQuery( hqlUpdate )
    .executeUpdate();
    //提交事務
    tx.commit();
    //關閉Session
    HibernateUtil.closeSession();
    }
    

    由 Query.executeUpdate()方法返回一個整型值,該值是受此操作影響的記錄數量。實際上,Hibernate的底層操作是通過JDBC完成的。因此,如果有批量的UPDATE或DELETE操作被轉換成多條UPDATE或DELETE語句,該方法返回的是最后一條SQL語句影響的記錄行數。

    posted on 2009-10-10 17:26 xiachang88 閱讀(284) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 欧美在线看片A免费观看| 亚洲一级免费视频| 免费欧洲美女牲交视频| 亚洲AV成人一区二区三区在线看| 伊人久久免费视频| 亚洲综合色丁香麻豆| 最近新韩国日本免费观看| 亚洲天天做日日做天天欢毛片| 国内少妇偷人精品视频免费| 亚洲午夜国产精品无码老牛影视 | 日韩免费在线中文字幕| 免费成人午夜视频| 一个人免费播放在线视频看片| 久久激情亚洲精品无码?V| 三级毛片在线免费观看| 亚洲色图在线观看| 中文字幕无码成人免费视频| 456亚洲人成影院在线观| 国产精品成人免费综合| japanese色国产在线看免费| 亚洲老妈激情一区二区三区| **一级一级毛片免费观看| 亚洲一区二区三区在线观看网站 | 免费精品一区二区三区第35| 伊人久久综在合线亚洲2019| 国产成人A在线观看视频免费| 久久精品国产亚洲av天美18| 在线亚洲精品福利网址导航| 91av视频免费在线观看| 亚洲成AV人影片在线观看| 国产亚洲美女精品久久久| 三年片在线观看免费大全电影 | 一区二区三区免费视频网站| 亚洲AV无码久久| 欧洲黑大粗无码免费| 亚欧乱色国产精品免费视频| 亚洲高清日韩精品第一区| 又爽又黄无遮挡高清免费视频| 久久精品私人影院免费看| 亚洲欧美综合精品成人导航| 国产亚洲一区二区三区在线|