總結: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=?