hibernate關聯對象的增刪改查------查,hibernate------

來源:互聯網
上載者:User

hibernate關聯對象的增刪改查------查,hibernate------

本篇部落格是之前部落格hibernate關聯對象的增刪改查------查 的後繼,本篇代碼的設定都在前文已經寫好,因此讀這篇之前,請先移步上一篇部落格

   


   //代碼片5
   

    SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();        Session session = sessionFactory.getCurrentSession();        session.beginTransaction();                    Dream d=new Dream();        d.setDescription("marry glt");                Person p=new Person();        p.setName("dlf");                d.setPerson(p);            session.save(d);        session.save(p);        session.getTransaction().commit();                        session = sessionFactory.getCurrentSession();        session.beginTransaction();        Dream dream=(Dream) session.get(Dream.class, 1);        System.out.println(dream.getPerson().getName()+"  ddddd");        session.getTransaction().commit();    


對應代碼5而言,get dream的時候發的sql語句為
 select        dream0_.id as id0_1_,        dream0_.description as descript2_0_1_,        dream0_.personId as personId0_1_,        person1_.id as id1_0_,        person1_.myname as myname1_0_    from        Dream dream0_    left outer join        Person person1_            on dream0_.personId=person1_.id    where        dream0_.id=?


換言之,get dream的時候,我們也獲得了對應的person。
有3個問題
1 執行代碼5的時候,dream的manytoone的cascade已經去掉了。
2 如果把Dream dream=(Dream) session.get(Dream.class, 1);與之前儲存對象的語句放到一個session裡,發的sql語句竟然是update。但是,System.out.println(dream.getPerson().getName()+"  ddddd");依然能輸入person的name。

我們能得出規律
在多對一,一對多的情況下,當我們讀取多的一方時,預設也會讀取一的一方。(這個規律與cascade無關)
反過來,如果我讀一的一方呢,會不會也自動讀出多的一方呢?
我們看代碼
        //代碼6    public void testGetPerson() {        Session s = sessionFactory.getCurrentSession();        s.beginTransaction();        Person p = (Person)s.get(Person.class, 2);        s.getTransaction().commit();        }
這個時候它發的sql語句是:
    select        person0_.id as id1_0_,        person0_.myname as myname1_0_    from        Person person0_    where        person0_.id=?
並沒有去主動獲得person對應的dream。
那如果我想獲得dream呢?
hibernate的管理關聯性中還有一個參數叫fetch。它管的就是在讀取某個對象時,是否需要讀取與之相關的另一個對象。
通過查閱api文檔,我們知道fetch的取值是fetchtype型的。而fetchtype是個Enum類型的。
可以取值LAZY與EAGER。

這個兩個值是什麼意思?
猜一猜,我們大概都是知道,eager就是主動擷取關聯對象的資料,lazy就是不擷取麼。
我只能說,大概是對的。
我們看代碼
在Person裡面修改OneToMany的屬性。
    @OneToMany(mappedBy="person",fetch=FetchType.EAGER)    public Set<Dream> getDreams() {        return dreams;    }
此時再運行代碼6,發的sql語句就是:
 select        person0_.id as id1_1_,        person0_.myname as myname1_1_,        dreams1_.personId as personId3_,        dreams1_.id as id3_,        dreams1_.id as id0_0_,        dreams1_.description as descript2_0_0_,        dreams1_.personId as personId0_0_    from        Person person0_    left outer join        Dream dreams1_            on person0_.id=dreams1_.personId    where        person0_.id=?
我們就能知道,如果想在取一的時候同時取多的一方,就在一的一方上加上fetch=feachType.eager。
那麼根據前面的代碼,我們就能推測出來
在預設情況下
一的那一方的fetch是lazy
多的那一方的fetch是eager
用eager修飾關聯關係:hibernate會發關聯的sql
用lazy修飾關聯關係:hibernate不會 主動發關聯sql
注意,我上面說的是 用lazy修飾關聯關係:hibernate不會發主動發關聯的sql
為什麼說主動呢?看看下面的代碼
我們改一改代碼6
    //代碼7    public void testGetPerson() {                Session s = sessionFactory.getCurrentSession();        s.beginTransaction();        Person p = (Person)s.get(Person.class, 2);        System.out.println(p.getDreams().size());        s.getTransaction().commit();    }
此時不設定person的fetch值。(保持預設的lazy)
此時發的sql語句是:
Hibernate:    select        person0_.id as id1_0_,        person0_.myname as myname1_0_    from        Person person0_    where        person0_.id=?Hibernate:    select        dreams0_.personId as personId1_,        dreams0_.id as id1_,        dreams0_.id as id0_0_,        dreams0_.description as descript2_0_0_,        dreams0_.personId as personId0_0_    from        Dream dreams0_    where        dreams0_.personId=?
此時我們可以得到一個結論,如果在session裡,我們只是獲得"一"的那一方,hibernate預設不會去取多的那一方;但是如果在session裡,訪問了獲得的"一"裡面"多"的那一方資料(就是訪問了person裡面的dream)。就會發關聯sql。

如此一來,就有了一個比較尷尬的事了
不管我在一的那一方設不設立fetch=FetchType.eager,我在session裡面獲得多的那一方的時候,都是可以的。
此時,還不如不設定fetch=FetchType.eager呢,因為有的時候,我確實不需要獲得多的那一方,如果一的那一方設定成eager,豈不是要多查詢很多無用的資料。

再看一個例子:
    //代碼8    public void testGetPerson() {                testSavePerson();                Session s = sessionFactory.getCurrentSession();        s.beginTransaction();        Person p = (Person)s.get(Person.class, 2);        s.getTransaction().commit();        System.out.println(p.getDreams().size());    }
就是把獲得多的那一方資料的代碼放到了session的外面。
如果此時person那邊還有fetch=FetchType.eager,那麼一切OK
螢幕上輸出:
Hibernate:    select        person0_.id as id1_1_,        person0_.myname as myname1_1_,        dreams1_.personId as personId3_,        dreams1_.id as id3_,        dreams1_.id as id0_0_,        dreams1_.description as descript2_0_0_,        dreams1_.personId as personId0_0_    from        Person person0_    left outer join        Dream dreams1_            on person0_.id=dreams1_.personId    where        person0_.id=?2   //dream的size是2
可是如果我把fetch=FetchType.eager去掉,在運行代碼8,就會報錯:
<span style="color:#FF0000;">failed to lazily initialize a collection of role: com.bjsxt.hibernate.Person.dreams, no session or session was closed</span>
說的很清楚,session已經關閉了。
為什麼呢?
我們知道,從person到dream,是一對多,而預設情況下,一對多的fetch是lazy的。
也就是說,正常情況下,取了pseron是不會再取dream。
我們注意代碼7發出的sql,是兩個。
現在我要獲得多的那方的命令,跑到了sesssion的外面,也就是說在session關閉後再去資料庫裡運行sql,那鐵定會報錯嘍。
我們再試試:
    //代碼9    public void testGetPerson() {                testSavePerson();                Session s = sessionFactory.getCurrentSession();        s.beginTransaction();        Person p = (Person)s.get(Person.class, 2);        s.getTransaction().commit();        System.out.println(p.getDreams().size());        s.getTransaction().commit();    }
此時的person的fetch還是預設的lazy。
是否會報錯呢?自己試試吧。


關於取對象這部分,hibernate還是比較麻煩的,我認為最好的方法就是保持預設的情況,一旦有了問題再查api文檔,或其他的資料。

那既然這樣,我為什麼還要寫這篇部落格呢?反正最好的方法就是保持預設情況嘛。

因為:

      世之奇偉、瑰怪、非常之觀,常在於險遠,而人之所罕至焉,故非有志者不能至也。





著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.