1. 程式人生 > >Hibernate學習(八)———— Hibernate檢索策略(類級別,關聯級別,批量檢索)詳解

Hibernate學習(八)———— Hibernate檢索策略(類級別,關聯級別,批量檢索)詳解

 序言

         很多看起來很難的東西其實並不難,關鍵是看自己是否花費了時間和精力去看,如果一個東西你能看得懂,同樣的,別人也能看得懂,體現不出和別人的差距,所以當你覺得自己看了很多書或者學了很多東西的時候,你要想想,你花費的也就那麼一點時間,別人花你這麼多時間也能夠學到你所學到的東西,所以還是要繼續努力。既然不是天才,唯有靠勤奮來彌補。

                                            --WH

 

一、概述

    檢索策略分三大塊,類級別檢索策略和關聯級別檢測策略。

        類級別檢索策略:get、load、

        關聯級別檢索策略:order.getCustomer().getName()

        上面這兩種應該是看得懂的。很容易去理解,現在就具體來說說這兩種其中的細節。

    批量檢索解決n+1問題。

二、類級別檢索策略

    2.1、立即檢索  get

        直接傳送sql語句,到資料庫中去查詢資料。

        例如                

 1 Staff staff = (Staff)session.get(Staff.class, 3);//執行完這句,就會發送sql語句,到資料庫表中查詢相應的資料加入一級快取中
 2 
 3 //結果
 4 Hibernate: 
 5     select
 6         staff0_.id as id1_0_,
 7         staff0_.name as name1_0_,
 8         staff0_.deptId as deptId1_0_ 
 9     from
10         staff staff0_ 
11     where
12         staff0_.id=?
複製程式碼
 1 Staff staff = (Staff)session.get(Staff.class, 3);//執行完這句,就會發送sql語句,到資料庫表中查詢相應的資料加入一級快取中
 2 
 3 //結果
 4 Hibernate: 
 5     select
 6         staff0_.id as id1_0_,
 7         staff0_.name as name1_0_,
 8         staff0_.deptId as deptId1_0_ 
 9     from
10         staff staff0_ 
11     where
12         staff0_.id=?
複製程式碼

        

    2.2、延遲檢索  load

        不會直接傳送sql語句,而是等到用的時候在傳送sql語句,如果一直沒用,就永遠不會發送sql語句。

1         Staff staff = (Staff)session.load(Staff.class, 3);//執行完這句,不會發送sql語句
 2         System.out.println("load後還沒傳送sql語句,等用到的時候才會傳送。");
 3         System.out.println(staff.getName());//現在需要用staff。則會發送sql語句。
 4 
 5 //結果
 6 
 7 load後還沒傳送sql語句,等用到的時候才會傳送。
 8 Hibernate: 
 9     select
10         staff0_.id as id1_0_,
11         staff0_.name as name1_0_,
12         staff0_.deptId as deptId1_0_ 
13     from
14         staff staff0_ 
15     where
16         staff0_.id=?
17 qqq2
複製程式碼
 1         Staff staff = (Staff)session.load(Staff.class, 3);//執行完這句,不會發送sql語句
 2         System.out.println("load後還沒傳送sql語句,等用到的時候才會傳送。");
 3         System.out.println(staff.getName());//現在需要用staff。則會發送sql語句。
 4 
 5 //結果
 6 
 7 load後還沒傳送sql語句,等用到的時候才會傳送。
 8 Hibernate: 
 9     select
10         staff0_.id as id1_0_,
11         staff0_.name as name1_0_,
12         staff0_.deptId as deptId1_0_ 
13     from
14         staff staff0_ 
15     where
16         staff0_.id=?
17 qqq2
複製程式碼

 

    2.3、深入講解get和load

        上面兩個只是簡單講解一下立即載入和延遲載入兩個概念。現在來講點深入的東西。

      1、load檢索返回的代理物件,而不是一個pojo物件,get返回的是pojo物件,這個的前提是一級快取中沒有我們要查詢的物件。

            

      2、get和load都是先從一級快取中拿資料,而不是每次都從資料庫中拿,也就是說如果一級快取有我們需要的資料,就不會在傳送sql語句了。並且返回就是一級快取物件中物件的狀態,也就是說如果在一級快取中該物件的狀態是pojo物件,那麼就算是用load載入的,返回的也就是pojo物件,如果該物件是代理物件,那麼就算get載入的,返回的也就是代理物件,不過會將代理物件的資料初始化。也就是會向資料庫中傳送sql語句查詢資料。           解釋:代理物件資料初始化:代理物件中包含了我們想要的pojo物件的所有資訊。

        例子:一級快取中的是代理物件,使用get獲得

 1         Staff staff = (Staff)session.load(Staff.class, 3);//staff代理物件加入快取中了
 2         System.out.println("沒有傳送sql語句,get之後就會發送。");
 3         Staff staff1 = (Staff)session.get(Staff.class, 3);//get獲取了快取中的代理物件,並且初始化
 4 
 5 //結果
 6 沒有傳送sql語句,get之後就會發送。
 7 Hibernate: 
 8     select
 9         staff0_.id as id1_0_,
10         staff0_.name as name1_0_,
11         staff0_.deptId as deptId1_0_ 
12     from
13         staff staff0_ 
14     where
15         staff0_.id=?
複製程式碼
 1         Staff staff = (Staff)session.load(Staff.class, 3);//staff代理物件加入快取中了
 2         System.out.println("沒有傳送sql語句,get之後就會發送。");
 3         Staff staff1 = (Staff)session.get(Staff.class, 3);//get獲取了快取中的代理物件,並且初始化
 4 
 5 //結果
 6 沒有傳送sql語句,get之後就會發送。
 7 Hibernate: 
 8     select
 9         staff0_.id as id1_0_,
10         staff0_.name as name1_0_,
11         staff0_.deptId as deptId1_0_ 
12     from
13         staff staff0_ 
14     where
15         staff0_.id=?
複製程式碼

              

         例子: 一級快取中是pojo物件,通過load獲得

 1         Staff staff = (Staff)session.get(Staff.class, 3);//staff pojo物件加入快取中了
 2         System.out.println("get後傳送sql語句,並且該pojo物件在一級快取中了。");
 3         Staff staff1 = (Staff)session.load(Staff.class, 3);//load獲取了快取中的pojo物件
 4 
 5 //結果
 6 Hibernate: 
 7     select
 8         staff0_.id as id1_0_,
 9         staff0_.name as name1_0_,
10         staff0_.deptId as deptId1_0_ 
11     from
12         staff staff0_ 
13     where
14         staff0_.id=?
15 get後傳送sql語句,並且該pojo物件在一級快取中了。
複製程式碼
 1         Staff staff = (Staff)session.get(Staff.class, 3);//staff pojo物件加入快取中了
 2         System.out.println("get後傳送sql語句,並且該pojo物件在一級快取中了。");
 3         Staff staff1 = (Staff)session.load(Staff.class, 3);//load獲取了快取中的pojo物件
 4 
 5 //結果
 6 Hibernate: 
 7     select
 8         staff0_.id as id1_0_,
 9         staff0_.name as name1_0_,
10         staff0_.deptId as deptId1_0_ 
11     from
12         staff staff0_ 
13     where
14         staff0_.id=?
15 get後傳送sql語句,並且該pojo物件在一級快取中了。
複製程式碼

              

 

      3、只有在使用時,代理物件才會初始化,其實還有一種方式可以不使用代理物件而初始化資料,

               

            因為沒有初始化代理物件,在關閉session後,在使用staff1,就會報錯,報錯內容為不能夠初始化程式碼物件,沒有session,

                

            使用Hibernate.initialize(proxy);來對代理物件進行初始化,這個的效果和使用代理物件是一樣的,但是會使程式碼看起來更好,如果你在這裡system.out.println(代理物件),也有也可以,但是看起來總覺得乖乖的,所以hibernate就有了這個方法來對代理物件進行初始化。

              

      4、可以通過lazy屬性來設定讓load不延遲載入,而跟get一樣立即載入,因為是類級別檢索,所以在hbm對映檔案中的class位置進行屬性設定。

               

            在staff.hbm.xml中設定了lazy=false。意思是讓其延遲載入失效,所以在對staff進行查詢時,使用load也是立即檢索

               

 

      5、我們常說的,get如果查詢資料庫中沒有的記錄的話,返回是null,而load將會報錯。這句話是正確的,但是概念很模糊,來看下面的路子看會不會報錯。

          例子一:查詢資料庫中沒有的資料,id=100,load的時候會不會報錯?  報錯           

              

          例子二:查詢資料庫中沒有的資料,id=100,並且將其取出id  不抱錯

              

          例子三:查詢資料庫中沒有的資料,id=100,並且取出name  報錯

              

            總結load:load載入返回的是一個代理物件,並且我們說的用load查詢一個數據庫中沒有的資料,並不是load這條語句報異常,而是在使用時,代理物件在資料庫表中找不到資料而報的異常,所以單純只寫load語句,是不會報錯的,並且代理物件的id是我們手動輸入進去的,不用往資料庫中查也知道,所以在代理物件.getId()時也不會發送sql語句,而是拿到我們一開始的id值。

 

       

 

 

    2.4、load和get的區別(面試題)

            1、get是立即載入、load是延遲載入

            2、get和load都是先從快取中查詢物件,如果有該物件的快取,則不向資料庫中查詢,並且返回的是快取中物件的狀態(是代理物件就返回代理物件,是pojo物件就返回pojo物件)

            3、在快取中沒有物件時,get返回的是pojo物件,load返回的是代理物件

 

三、關聯級別檢索策略

    在<set>標籤上或者在<many-to-one>上設定兩個屬性值來控制其檢索策略,  fetch、lazy

          fetch:代表檢索時的語句的方式,比如左外連線等。

              fetch:join、select 、subselect  

          lazy:是否延遲載入。

              lazy:true、false、extra

    分兩種情況

    3.1、一對多或多對多時

        <set fetch="",lazy="">

        fetch = join時,採取迫切左外連線查詢  

              lazy不管取什麼值都失效,就是取預設值為false。

        fetch=select時,生成多條簡單sql查詢語句

              lazy=false:立即檢索

              lazy=true:延遲檢索

              lazy=extra:加強延遲檢索,非常懶惰,比延遲檢索更加延遲

        fetch=subselect時,生成子查詢

              lazy=false:立即檢索

              lazy=true;延遲檢索

              lazy=extra:加強延遲檢索,非常懶惰,比延遲檢索更加延遲

 

       實驗一:fetch=join 傳送左外迫切連線

          一、hql的query查詢

                  

        使用hql的query查詢,會讓fetch=join失效,lazy重新啟用。如果生成結果是延遲檢索,那麼就說明我們說的這個是正確的。

1         //使用hql查詢,fetch=join是無效的,並且lazy重新啟用,本來lazy失效的話,
 2         //則使用預設的,就是立即載入,現在因為重新啟用了,所以會是延遲載入
 3         Query query = session.createQuery("from Dept where id = 2");
 4         Dept dept = (Dept) query.uniqueResult();
 5         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 6         dept.getStaffSet().size();
 7 
 8 //結果
 9 
10 Hibernate: 
11     select
12         dept0_.id as id0_,
13         dept0_.name as name0_ 
14     from
15         dept dept0_ 
16     where
17         dept0_.id=2
18 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
19 Hibernate: 
20     select
21         staffset0_.deptId as deptId0_1_,
22         staffset0_.id as id1_,
23         staffset0_.id as id1_0_,
24         staffset0_.name as name1_0_,
25         staffset0_.deptId as deptId1_0_ 
26     from
27         staff staffset0_ 
28     where
29         staffset0_.deptId=?
複製程式碼
 1         //使用hql查詢,fetch=join是無效的,並且lazy重新啟用,本來lazy失效的話,
 2         //則使用預設的,就是立即載入,現在因為重新啟用了,所以會是延遲載入
 3         Query query = session.createQuery("from Dept where id = 2");
 4         Dept dept = (Dept) query.uniqueResult();
 5         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 6         dept.getStaffSet().size();
 7 
 8 //結果
 9 
10 Hibernate: 
11     select
12         dept0_.id as id0_,
13         dept0_.name as name0_ 
14     from
15         dept dept0_ 
16     where
17         dept0_.id=2
18 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
19 Hibernate: 
20     select
21         staffset0_.deptId as deptId0_1_,
22         staffset0_.id as id1_,
23         staffset0_.id as id1_0_,
24         staffset0_.name as name1_0_,
25         staffset0_.deptId as deptId1_0_ 
26     from
27         staff staffset0_ 
28     where
29         staffset0_.deptId=?
複製程式碼

          二、使用get查詢。fetch=join生效,lazy就會失效,並且會發送左外迫切連線。這裡要注意,要看set中存放的東西是什麼,而不是看傳送的語句是不是含有fetch來判斷是不是左外迫切連線,因為hibernate中,左外迫切連線傳送的語句跟左外連線傳送的語句是一樣的,從這裡是區分不出來了。如果不信的話,自己可以去嘗試一下,手動寫一個左外迫切連線,然後看傳送的語句是什麼樣的,我試過了,跟我說的一樣

 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_1_,
10         dept0_.name as name0_1_,
11         staffset1_.deptId as deptId0_3_,
12         staffset1_.id as id3_,
13         staffset1_.id as id1_0_,
14         staffset1_.name as name1_0_,
15         staffset1_.deptId as deptId1_0_ 
16     from
17         dept dept0_ 
18     left outer join
19         staff staffset1_ 
20             on dept0_.id=staffset1_.deptId 
21     where
22         dept0_.id=?
23 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
24 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼
 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_1_,
10         dept0_.name as name0_1_,
11         staffset1_.deptId as deptId0_3_,
12         staffset1_.id as id3_,
13         staffset1_.id as id1_0_,
14         staffset1_.name as name1_0_,
15         staffset1_.deptId as deptId1_0_ 
16     from
17         dept dept0_ 
18     left outer join
19         staff staffset1_ 
20             on dept0_.id=staffset1_.deptId 
21     where
22         dept0_.id=?
23 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
24 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼

          總結第一種情況fetch=join。

              1、注意我們這裡討論的是關聯級別的檢索方式,所以重點是看關聯的時候傳送的sql語句,重心不在get和load上面了

              2、fetch=join讓lazy失效的前提是使用的不是hql的query查詢。

       實驗二:fetch=select時 傳送簡單sql語句

            lazy=false;也就是立即檢索,傳送簡單sql語句

                     

複製程式碼
 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 Hibernate: 
16     select
17         staffset0_.deptId as deptId0_1_,
18         staffset0_.id as id1_,
19         staffset0_.id as id1_0_,
20         staffset0_.name as name1_0_,
21         staffset0_.deptId as deptId1_0_ 
22     from
23         staff staffset0_ 
24     where
25         staffset0_.deptId=?
26 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
27 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼  
 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 Hibernate: 
16     select
17         staffset0_.deptId as deptId0_1_,
18         staffset0_.id as id1_,
19         staffset0_.id as id1_0_,
20         staffset0_.name as name1_0_,
21         staffset0_.deptId as deptId1_0_ 
22     from
23         staff staffset0_ 
24     where
25         staffset0_.deptId=?
26 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
27 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
   

            lazy=true;延遲檢索,傳送簡單sql語句

                   

  

 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
16 Hibernate: 
17     select
18         staffset0_.deptId as deptId0_1_,
19         staffset0_.id as id1_,
20         staffset0_.id as id1_0_,
21         staffset0_.name as name1_0_,
22         staffset0_.deptId as deptId1_0_ 
23     from
24         staff staffset0_ 
25     where
26         staffset0_.deptId=?
27 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼
 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
16 Hibernate: 
17     select
18         staffset0_.deptId as deptId0_1_,
19         staffset0_.id as id1_,
20         staffset0_.id as id1_0_,
21         staffset0_.name as name1_0_,
22         staffset0_.deptId as deptId1_0_ 
23     from
24         staff staffset0_ 
25     where
26         staffset0_.deptId=?
27 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼

            lazy=extra;超級懶惰,能儘量少查就絕對不會多查,比如,size(),就會使用count()函式,而不會全部查表中的欄位,就是這個意思

                    

1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set.size());
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
16 Hibernate: 
17     select
18         count(id) 
19     from
20         staff 
21     where
22         deptId =?
23 9
複製程式碼
 1         Dept dept = (Dept) session.get(Dept.class, 2);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set.size());
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_0_,
10         dept0_.name as name0_0_ 
11     from
12         dept dept0_ 
13     where
14         dept0_.id=?
15 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
16 Hibernate: 
17     select
18         count(id) 
19     from
20         staff 
21     where
22         deptId =?
23 9
複製程式碼

 

        實驗三、fetch=subselect 生成子查詢,注意使用get方式不生成子查詢,使用query().list().get(),並且資料庫表中還得不止一條記錄才會生成子查詢,如果只有一條記錄,hibernate也很聰明,就沒必要用子查詢了。

            lazy=false:立即檢索

 1         Dept dept = (Dept) session.createQuery("from Dept").list().get(0);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_,
10         dept0_.name as name0_ 
11     from
12         dept dept0_
13 Hibernate: 
14     select
15         staffset0_.deptId as deptId0_1_,
16         staffset0_.id as id1_,
17         staffset0_.id as id1_0_,
18         staffset0_.name as name1_0_,
19         staffset0_.deptId as deptId1_0_ 
20     from
21         staff staffset0_ 
22     where
23         staffset0_.deptId in (
24             select
25                 dept0_.id 
26             from
27                 dept dept0_
28         )
29 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
30 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼
 1         Dept dept = (Dept) session.createQuery("from Dept").list().get(0);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Set<Staff> set = dept.getStaffSet();
 4         System.out.println(set);
 5 
 6 //結果
 7 Hibernate: 
 8     select
 9         dept0_.id as id0_,
10         dept0_.name as name0_ 
11     from
12         dept dept0_
13 Hibernate: 
14     select
15         staffset0_.deptId as deptId0_1_,
16         staffset0_.id as id1_,
17         staffset0_.id as id1_0_,
18         staffset0_.name as name1_0_,
19         staffset0_.deptId as deptId1_0_ 
20     from
21         staff staffset0_ 
22     where
23         staffset0_.deptId in (
24             select
25                 dept0_.id 
26             from
27                 dept dept0_
28         )
29 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
30 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼

            lazy=true:延遲檢索

            lazy=extra;超級懶惰,比延遲檢索還延遲

                這兩個其實也就差不多了,自己可以試試

           

    3.2、多對一或一對一時

        fetch可以取值為:join,select

        lazy:false,proxy,no-proxy

        當fetch=join,lazy會失效,生成的sql是迫切左外連線

              如果我們使用query時,hql是我們自己指定的,那麼fetch=join是無效的,不會生成迫切左外連線,這時lazy重新啟用

        當fetch=select,lazy不失效,生成簡單sql語句,

            lazy=false:立即檢索

            lazy=proxy:這時關聯物件採用什麼樣的檢索策略取決於關聯物件的類級別檢索策略.就是說參考<class>上的lazy的值

 

        其實跟上面一樣,我們是測試一個fetch=select,lazy=proxy的把。

        staff,也就是多方,

            

        dept,也就是一方

                

        按照我們所配置的,關聯級別檢索應該是延遲檢索,結果正如我們所想的。

1         Staff staff = (Staff) session.createQuery("from Staff").list().get(0);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Dept dept = staff.getDept();
 4         System.out.println(dept);
 5 //結果
 6 Hibernate: 
 7     select
 8         staff0_.id as id1_,
 9         staff0_.name as name1_,
10         staff0_.deptId as deptId1_ 
11     from
12         staff staff0_
13 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
14 Hibernate: 
15     select
16         dept0_.id as id0_0_,
17         dept0_.name as name0_0_ 
18     from
19         dept dept0_ 
20     where
21         dept0_.id=?
22 Dept [id=2, name=1部門]
複製程式碼
 1         Staff staff = (Staff) session.createQuery("from Staff").list().get(0);
 2         System.out.println("如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入");
 3         Dept dept = staff.getDept();
 4         System.out.println(dept);
 5 //結果
 6 Hibernate: 
 7     select
 8         staff0_.id as id1_,
 9         staff0_.name as name1_,
10         staff0_.deptId as deptId1_ 
11     from
12         staff staff0_
13 如果sql語句在這句話之上說明是立即載入,如果在之下就是延遲載入
14 Hibernate: 
15     select
16         dept0_.id as id0_0_,
17         dept0_.name as name0_0_ 
18     from
19         dept dept0_ 
20     where
21         dept0_.id=?
22 Dept [id=2, name=1部門]
複製程式碼

 

 

        總結:

          1、為什麼需要分(一對多,多對多)和(多對一,一對一)兩組情況呢?

              注意:這裡說的一對多,那麼就是單向一對多,也就是佔在一的角度去考慮東西,上面說的四種都是從左邊往右邊看。

              因為一對多和多對多,所拿到的關聯物件度是一個集合,查詢的記錄就有很多個,也就多了一個fetch=subselect這個特性,查詢方式的變化也就多一點,

              而多對一,一對一,所拿到的關聯物件就是一個物件,也就是一條記錄,查詢的方式比較單一和簡單

              因為上面的原因就把他們兩個給分開來以處理不同的情況。達到更高的效率。

          2、為什麼需要搞這樣的檢索方式,不很麻煩嗎?

              根據不同的業務需求,來讓開發者自己控制用什麼樣的檢索方式,這樣讓程式的效能更好

 

四、批量檢索

      什麼叫批量檢索,就是多條sql語句才能完成的查詢,現在一條sql語句就能解決多條sql語句才能完成的事情,看下面例子就明白了,

      例子:n+1問題,什麼叫n+1問題?

         就拿我們上面這個例子來說,Dept和Staff,現在有5個部門,每個部門中的人數可能一樣,也可能不一樣,要求,查詢每個部門中的員工。那麼我們寫的話就需要傳送6條sql語句,哪6條呢?第一條查詢部門表中所有的部門,剩下5條,拿到每一個部門的ID,去員工表中查詢每個部門中的員工,要查5次,因為有5個部門。本來只有5個部門,現在需要傳送6條sql語句,這就是n+1問題,看下面程式碼

         總之就傳送了6條sql語句,我已經數過了。

 1         List<Dept> list = session.createQuery("from Dept").list();
 2         
 3         for(Dept dept : list){
 4             System.out.println(dept.getStaffSet());
 5         }
 6 
 7 //結果
 8 Hibernate: 
 9     select
10         dept0_.id as id0_,
11         dept0_.name as name0_ 
12     from
13         dept dept0_
14 Hibernate: 
15     select
16         staffset0_.deptId as deptId0_1_,
17         staffset0_.id as id1_,
18         staffset0_.id as id1_0_,
19         staffset0_.name as name1_0_,
20         staffset0_.deptId as deptId1_0_ 
21     from
22         staff staffset0_ 
23     where
24         staffset0_.deptId=?
25 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
26 Hibernate: 
27     select
28         staffset0_.deptId as deptId0_1_,
29         staffset0_.id as id1_,
30         staffset0_.id as id1_0_,
31         staffset0_.name as name1_0_,
32         staffset0_.deptId as deptId1_0_ 
33     from
34         staff staffset0_ 
35     where
36         staffset0_.deptId=?
37 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
38 Hibernate: 
39     select
40         staffset0_.deptId as deptId0_1_,
41         staffset0_.id as id1_,
42         staffset0_.id as id1_0_,
43         staffset0_.name as name1_0_,
44         staffset0_.deptId as deptId1_0_ 
45     from
46         staff staffset0_ 
47     where
48         staffset0_.deptId=?
49 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
50 Hibernate: 
51     select
52         staffset0_.deptId as deptId0_1_,
53         staffset0_.id as id1_,
54         staffset0_.id as id1_0_,
55         staffset0_.name as name1_0_,
56         staffset0_.deptId as deptId1_0_ 
57     from
58         staff staffset0_ 
59     where
60         staffset0_.deptId=?
61 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
62 Hibernate: 
63     select
64         staffset0_.deptId as deptId0_1_,
65         staffset0_.id as id1_,
66         staffset0_.id as id1_0_,
67         staffset0_.name as name1_0_,
68         staffset0_.deptId as deptId1_0_ 
69     from
70         staff staffset0_ 
71     where
72         staffset0_.deptId=?
73 [[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]]
複製程式碼
 1         List<Dept> list = session.createQuery("from Dept").list();
 2         
 3         for(Dept dept : list){
 4             System.out.println(dept.getSta