天天看點

hibernate之inverse、cascade----同時儲存主從表資訊

總結:inverse不讓主表對象生成快照和緩存時生成外鍵那部分資訊,進而達到兩個save語句執行後隻會有兩條insert語句而不會有update語句;cascade(級聯)是為了隻寫一句save就能同時儲存主從表資訊。

這是inverse部分:

如果我們需要新增一個user和一個dog,而這個dog正好屬于這個user,那麼我們會這麼寫:

@org.junit.Test
  public void test() {
    Session sesission = SessionFactoryUtils.getSessionFactory().getCurrentSession();
    Transaction tx = sesission.beginTransaction();
    User user = new User();
    user.setUsername("xixixi");
    Dog dog = new Dog();
    dog.setDogname("哈士奇");
    user.getDogs().add(dog);
    dog.setDogmaster(user);
    sesission.save(user);//語句1
    sesission.save(dog);//語句2
    tx.commit();
  }      

這樣執行的結果是執行兩條insert語句和一條update語句,其中update語句如下:

update dog set dogmaster = ? where dogid = ?      

為什麼?因為在執行完語句1之後,馬上會在session中産生一級緩存和快照,這時候user中的那個dog還是沒有OID的,然後當執行完語句2之後,馬上傳回一個dog,此時的dog已經有了OID,而這個dog和剛才那個一級緩存當中的user中的dog是同一對象(但快照中的那個user的内容是不會改變的,那是拷貝的),是以一級緩存中的user對象也随之改變了,然後hibernate再對dog做緩存和快照。從上面可以看出,在commit的時候,會檢測到user發生了變化,而dog不受影響,故會執行後面的update語句。

那為什麼會是上面那種update方式,就隻更新一個字段呢?始終記住,dogs屬性隻不過是User對象用來表達外鍵的一種方式,是以它的資訊也就是象征着Dog表中dogmaster那個字段的資訊,是以還有必要去寫update(dog)來更新全字段嘛?根本不用啊,是以它隻要更新Dog表中那條記錄的外鍵就可以了,因為整個這條記錄的資訊都記錄在dog對象裡裡,是以擷取參數dogmaster 和 dogid自然很容易了。細想後你發現,這個update語句完全沒有存在的必要,因為語句2執行完後Dog表中的記錄已經完整了,此時在一級緩存中的dog就是資料庫中的真實記錄,然後你又根據它去做update操作,這不是廢話?

最後解決方法,簡單了,在User.hbm.xml的Set标簽下配置一下inverse屬性為true,讓user在生成快照時放棄生成外鍵那部分快照即可:

<set name="dogs" table="dog" inverse="true">
          <key column="dogmaster"></key>
          <one-to-many class="Dog"/>
        </set>      

這是cascade:

還是上面的例子,我現在想隻寫一句save就同時儲存住表、從表資訊,行不行呢?答案是可以! 因為你想嘛,user對象裡有dog,dog對象裡也有user,從理論上來說肯定可以實作,那麼我們這麼寫:

<!-- 就是這個cascade屬性起了作用,值save-update代表儲存更新操作都會級聯執行。 -->
        <set name="dogs" table="dog"  inverse="true" cascade="save-update">
          <key column="dogmaster"></key>
          <one-to-many class="Dog"/>
        </set>      

然後 session.save(user);

再或者這麼寫:

<many-to-one name="dogmaster" column="dogmaster" class="User" cascade="save-update"></many-to-one>      
Hibernate: 
    insert 
    into
        user
        (username, password) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        dog
        (dogname, dogcolor, dogage, dogmaster) 
    values
        (?, ?, ?, ?)
Sun Jul 01 10:50:59 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended.
Hibernate: 
    update
        dog 
    set
        dogmaster=? 
    where
        dogid=?