hibernate學習筆記3 —— 批量更新 檢索策略

批量更新:

1)session => jdbc-bache-size=?   10至50間爲佳

<property name="jdbc.batch_size">20</property><!-- Hibernate的配置文件中設置JDBC單次批量處理的數目,合理的取值通常爲10到50之間 -->


// 測試
		for (int i = 1; i <= 100; i++) {
			// 對象
			Depts depts = new Depts(new Long(i), "T" + i);
			// 保存
			session.save(depts);

			// 判斷
			if (i % 20 == 0) {// 單次批量操作的數目爲20
				session.flush(); // 清理緩存,執行批量插入20條記錄的SQL insert語句
				session.clear(); // 清空緩存中的Depts對象
			}
		}

批量添加、更新、刪除時需要適當的清理緩存。

首先需要關閉hibernate 二次緩存。


2)hql進行批量更新(HQL只支持insert into ... select ...形式的插入語句,而不支持"insert into ... values ... "形式的插入語句。)

String hql="update Dept set d.dname='IT'";

session.createQuery().executeUpdate();

String hql="insert into Depts(deptno,dname) select d.deptno,d.dname from Dept d";

3)jdbc來執行批量更新

// sql語句
		final String sql = "update Depts d set d.dname='IT'";
		
		//定義一個匿名類,實現了Work接口
		Work work=new Work() {
			
			@Override
			public void execute(Connection connection) throws SQLException {
				
				PreparedStatement ps = connection.prepareStatement(sql);
				
				ps.execute();
				
			}
		};
		
		//執行work////
		session.doWork(work);

以上批量更新方式有兩個缺點:
佔用大量內存,必須把1萬個Customer對象先加載到內存,然後一一更新它們。
執行的update語句的數目太多,每個update語句只能更新一個Customer對象,必須通過1萬條update語句才能更新1萬個Customer對象,頻繁地訪問數據庫,會大大降低應用的性能。


一般說來,應該儘可能避免在應用層進行批量操作,而應該在數據庫層直接進行批量操作,例如直接在數據庫中執行用於批量更新或刪除的SQL語句,如果批量操作的邏輯比較複雜,則可以通過直接在數據庫中運行的存儲過程來完成批量操作。
並不是所有的數據庫系統都支持存儲過程。例如目前的MySQL就不支持存儲過程,因此不能通過存儲過程來進行批量更新或批量刪除。
當然,在應用層也可以進行批量操作,主要有以下方式:


(1)通過Session來進行批量操作。

      注意:

   (a)需要在Hibernate的配置文件中設置JDBC單次批量處理的數目,合理的取值通常爲10到50之間,例如:hibernate.jdbc.batch_size=20

   (b)Hibernate的第二級緩存是關閉的,此外也可以在Hibernate的配置文件中通過如下方式顯式關閉第二級緩存:hibernate.cache.use_second_level_cache=false



(3)通過HQL來進行批量操作。

  HQL(Hibernate Query Language,Hibernate查詢語言)不僅可以檢索數據,

  還可以用於進行批量更新、刪除和插入數據。批量操作實際上直接在數據庫中完成,所處理的數據不會被保存在Session的緩存中,因此不會佔用內存空間。


(4)直接通過JDBC API來進行批量操作。

   當通過JDBC API來執行SQL insert、update和delete語句時,SQL語句中涉及到的數據不會被加載到內存中,因此不會佔用內存空間。

以下程序直接通過JDBC API來執行用於批量更新的SQL語句:

值得注意的是,在Hibernate3中,儘管Session的connection()方法還存在,但是已經被廢棄,不提倡使用了,

不過Hibernate3提供了替代方案:org.hibernate.jdbc.Work接口表示直接通過JDBC API來訪問數據庫的操作,

Work接口的execute()方法用於執行直接通過JDBC API來訪問數據庫的


HIbernate 檢索策略:

檢索策略                            運行機制

立即檢索                           立即加載與當前對象並聯的對象,需要執行多條select語句      n+1條語句

延遲檢索                           不立即加載與當前對象關係關聯的對象,在第一次訪問關聯對象時才加載其信息

迫切左外連接檢索           通過左外連接加載與當前對象的關聯對象爲立即檢索策略,但執行的select語句少,只執行1條select連接查詢語句


查詢:   lazy="true"   延遲查詢

load()          僅影響session的load()方法

lazy 屬性默認爲true    即進行延遲加載。


延遲查詢:在實際調用查詢結果時檢索

立即查詢:在調用load/get時檢索


Session get()  /  load()

檢索策略包括:

1)類級別 lazy = "true"

對於Session的檢索方式,類級別檢索策略僅適用於load方法 ;也就說,對於get、qurey檢索,持久化對象都會被立即加載而不管lazy是false還是true。

 一 般來說,我們檢索對象就是要訪問它,因此立即檢索是通常的選擇。由於load方法在檢索不到對象時會拋出異常(立即檢索的情況下),因此我個人並不建議使 用load檢

索;而由於<class>中的lazy屬性還影響到多對一及一對一的檢索策略,因此使用load方法就更沒必要了

2)關聯級別 lazy="true"

有立即檢索、延遲檢索和迫切左外連接檢索。

對於關聯級別檢索,又可分爲一對多和多對多、多對一和一對一兩種情況討論。

 一對多和多對多關聯關係一般使用<set>配置。<set>有lazy和outer-join屬性,它們的不同取值絕對了檢索策略。

1)立即檢索:這是一對多默認的檢索策略,此時lazy=false,outer-join=false.儘管這是默認的檢索策略,但如果關聯的集合是無用的,那麼就不要使用這種檢索方式。

2)延遲檢索:此時lazy=true,outer-join=false(outer-join=true是無意義的),這是優先考慮的檢索方式。

3)迫切左外連接檢索:此時 lazy=false,outer-join=true,這種檢索策略只適用於依靠id檢索方式(load、get),而不適用於query的集合檢索 (它會採用立即檢索策略)。相

比於立即檢索,這種檢索策略減少了一條sql語句,但在Hibernate中,只能有一個<set>配置成 outer-join=true.

 多對一和一對一檢索策略一般使用<many-to-one>、<one-to-one>配置。<many- to-one>中需要配置的屬性是 outer-join,同時還需要配置one端關聯的<class>的lazy屬性

(配置的可不是<many-to-one>中 的lazy哦),它們的組合後的檢索策略如下:

1) outer-join=auto:這是默認值,如果lazy=true爲延遲檢索,如果lazy=false爲迫切左外連接檢索。

2) outer-join=true,無關於lazy,都爲迫切左外連接檢索。

3) outer-join=false,如果lazy=true爲延遲檢索,否則爲立即檢索。

可以看到,在默認的情況下(outer-join=auto,lazy=false),對關聯的one端對象Hibernate採用的迫切左外連接檢索。 依我看,很多情況下,我們並不需要加載one端關聯的

對象(很可能我們需要的僅僅是關聯對象的id);另外,如果關聯對象也採用了迫切左外連接檢索,就會 出現select語句中有多個外連接表,如果個數多的話會影響檢索性能,

這也是爲什麼Hibernate通過 hibernate.max_fetch_depth屬性來控制外連接的深度。對於迫切左外連接檢索,query的集合檢索並不適用,它會採用立即檢索策 略。

 對於檢索策略,需要根據實際情況進行選擇。對於立即檢索和延遲檢索,它們的優點在於select語句簡單(每張表一條語句)、查詢速度快,缺點在於關聯表 時需要多條select

語句,增加了訪問數據庫的頻率。因此在選擇即檢索和延遲檢索時,可以考慮使用批量檢索策略來減少select語句的數量(配置 batch-size屬性)。對於切左外連接檢索,優點

在於select較少,但缺點是select語句的複雜度提高,多表之間的關聯會是很耗時的操作。 另外,配置文件是死的,但程序是活的,可以根據需要在程序裏顯示的指定檢索策略

(可能經常需要在程序中顯示指定迫切左外連接檢索)。爲了清楚檢索策略的配 置效果如何,可以配置show_sql屬性查看程序運行時Hibernate執行的sql語句。 

詳細可查看:點擊打開鏈接



發佈了26 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章