單一數據加載:Session.get/load
          均可以根據指定的實體類和id從數據庫中讀取記錄,并返回與之對應的實體對象。
          區別:
          1.如果未能發現符合條件的記錄,get方法返回null,而load方法會拋出一個ObjectNotFoundException。
          2.Load方法可返回實體的代理類實例,而get方法永遠直接返回實體類。
          3.load方法可以充分利用內部緩存和二級緩存中的現有數據,而get方法僅在內部緩存中查找,如果沒有發現對應的數據,將越過二級緩存,直接調用SQL完成數據讀取。
          數據加載的過程:
          1.在一級緩存中,根據實體類型和id進行查找,如果在第一級緩存中命中,且數據狀態合法,則直接返回。
          2.Session會在當前"NonExists"記錄中進行查找,如果在"NonExists"記錄中存在同樣的條件,返回null。
          3.對load方法而言,如果內部緩存中沒法現有效數據,查詢二級緩存,命中則返回。
          4.如果緩存中無有效數據,發起數據庫查詢操作(Select SQL),如果經過查詢未發現對應記錄,將此次查詢的信息在"NonExists"中加以記錄,返回null.
          5.根據映射配置和Select SQL查詢得到的ResultSet,創建對應的數據對象。
          6.將對象納入一級緩存。
          7.執行Interceptor.onLoad方法(如果有對應的Interceptor)
          8.將數據納入二級緩存
          9.如果數據對象實現了LifeCycle接口,則調用數據對象的onLoad方法。
          10.返回數據對象。


          批量查詢:Session.find/iterate
          查詢性能往往是系統性能表現的一個重要方面,查詢機制的優劣很大程度上決定了系統的整體性能。這個領域往往也存在最大的性能調整空間。

          hibernate2中Session.find()對應于3中的session.createQuery().list();
          hibernate2中Session.iterate()對應于3中的session.createQuery().iterate();
          find和iterate區別:
          find方法通過一條Select SQL實現了查詢操作,而iterate方法要執行多條Select SQL.
          iterate第一次查詢獲取所有符合條件的記錄的id,然后再根據各個id從庫表中讀取對應的記錄,這是一個典型的N+1次的查詢問題,如果符合條件記錄有10000條,就需要執行10001條Select SQL,可想性能會如何的差。

          那為什么要提供iterator方法,而不只是提供高效率的find方法?

          原因1.與hibernate緩存機制密切相關
          find方法實際上是無法利用緩存的,它對緩存只寫不讀。
          find方法只執行一次SQL查詢,它無法判斷緩存中什么樣的數據是符合條件的,也無法保證查詢結果的完整性。而iterate方法,會首先查詢所有符合條件記錄的id,然后根據id去緩存中找,如果緩存中有該id,就返回,沒有可以根據id再去數據庫查詢。
          String hql = "from TUser where age > ?";
          List userList = session.find(hql, new Integer(18), Hibernate.INTEGER);
          Iterator it = session.iterate(hql, new Integer(18), Hibernate.INTEGER);
          順序執行,iterate方法只會執行一次SQL查詢,就是查找id,然后根據id就可以從緩存中獲得數據。

          String hql = "from TUser where age > ?";
          List userList = session.find(hql, new Integer(18), Hibernate.INTEGER);
          userList = session.find(hql, new Integer(18), Hibernate.INTEGER);
          緩存是不起作用的。
          如果目標數據讀取相對較為頻繁,通過iterate這種機制,會減少性能損耗。

          原因2.內存使用上的考慮
          find方法將一次獲得的所有記錄并將其讀入內存。如果數據量太大,可能會觸發OutOfMemoryError,從而導致系統異常。解決方案之一就是結合iterate方法和evict方法逐條對記錄進行處理,將內存消化保持在一個可以接受的范圍之內。如:
          String hql = "from TUser where age > ?";
          Iterator it = session.iterate(hql, new Integer(18), Hibernate.INTEGER);
          while(it.hasNext()) {
          ??? TUser user = (TUser)it.next();
          ???
          ??? //將對象從一級緩存中刪除
          ??? session.evict(user);

          ??? //二級緩存可以設定最大緩存量,達到后自動對較老數據進行廢除,但也可以通過編
          ??? //碼移除,這樣有助于保持數據有效性。
          ??? sessionFactory.evict(TUser.class, user.getID());
          }


          批量數據處理的緩存同步問題
          1.hibernate 2:
          session.delete("from TUser");
          會先查詢出id,然后逐個id執行 delete from T_User where id = ?;
          這樣造成效率低下。
          為什么不直接采用一條Delete SQL?是因為ORM要自動維持其內部狀態屬性,必須知道用戶作了什么操作。必須先從數據庫中獲得待刪除對象,然后根據這些對象對內部緩存和二級緩存的數據進行整理,以保持內存狀態與數據庫的一致性。
          單執行一條刪除語句,刪除了什么數據,只有數據庫知道,ORM無法得知。下次用戶從緩存中讀出的數據,很可能就是被刪除的數據,從而導致邏輯錯誤。當然,如果ORM可以根據DELETE SQL對緩存中數據進行處理,將緩存中符合條件的對象廢除,然后再執行DELETE SQL
          ,但是這樣導致緩存的管理復雜性大大增加(實際相當于實現了一個支持SQL的內存數據庫),這對于輕量級的ORM實現而言太苛刻了。
          2.hibernate 3
          性能提高。
          但無法解決緩存同步上的問題,無法保證緩存數據的一致有效性。
          Tuser user = (TUser)session.load(TUser.class, new Integer(1));

          //通過Bulk delete/update 刪除id=1的用戶記錄
          Transaction tx = session.beginTransaction();
          String hql = "delete TUser where id=1";
          Query query = session.createQuery(hql);
          query.executeUpdate();
          tx.commit();

          //再次嘗試加載
          user = (TUser)session.load(TUser.class, new Integer(1));
          可以看到第二次加載是成功的。

          posted on 2006-07-16 10:24 knowhow 閱讀(424) 評論(0)  編輯  收藏 所屬分類: ORM:Hibernate及其他
          主站蜘蛛池模板: 新蔡县| 平阴县| 红河县| 玉环县| 芒康县| 中西区| 长沙市| 西林县| 温泉县| 越西县| 信丰县| 齐齐哈尔市| 铜鼓县| 东辽县| 会理县| 敖汉旗| 深水埗区| 祁连县| 明水县| 巴马| 宁都县| 长白| 泗阳县| 墨竹工卡县| 如皋市| 惠来县| 托克逊县| 富锦市| 远安县| 富平县| 甘泉县| 礼泉县| 湟源县| 六枝特区| 丹寨县| 施秉县| 阳谷县| 榆中县| 恩平市| 肇源县| 波密县|