public class Book {
private Long id;
private BookType type;
}
public class BookType {
private Long id;
}
好了,我們開始
情況一
它們相互不關聯
情況二
/**
* @hibernate.many-to-one column="col_booktype_id"
*/
public BookType getType() {
return type;
}
也就是說,一個類有多本書,比如有很多書是歷史類別,很多其他書是數學類別,非常好理解
那麼:
BookType bookType = new BookType();
Book book1 = new Book();
book1.setType(bookType);
Book book2 = new Book();
book2.setType(bookType);
bookService.save(book1);
bookService.save(book2);
先創建一個 “書本類” 的實例,再創建 2本書,都是屬於這本書,保存這2本書,結果出錯。爲什麼?因爲沒有把BookTpye保存,所以那2本書的類別字段就不能保存了。這時cascade登場了——
cascade有2個級別 cascade=“save-update” cascade=“delete” 我們先來看 cascade=“save-update”
/**
* @hibernate.many-to-one column="col_booktype_id" cascade=“save-update”
*/
public BookType getType() {
return type;
}
這時,在保存book1的時候自動能把booktype也保存掉,在保存book2的時候,發現booktype已經存在了,於是去更新了booktype,總之要級聯過去。
所以說,其實這個功能是比較偷懶的功能,呵呵。
好了,現在我們來看看 cascade=“delete”
假設上述已經都保存完畢,那麼把book1刪除,OK……接着刪除book2,這時,它會先去刪除booktype,再刪除book2,可見就是這個意思。Hibernate會認爲,你歷史類的書都沒了,我還要歷史這個類幹嘛用?於是都刪了。
情況三
那麼現在我們有一個新的需求了,要通過booktype去得到book,比如 getBooks(“歷史”) 返回一個book的Set,在沒有Hibernate這些框架的時代,我們要先去 booktype表,找歷史的那個id,再拿這個Id去book中,把這些book給找出來,當然,有了Hibernate,其實內部也是這麼執行的,只是大大簡化了我們的編碼量。好!那麼這個當然是屬於 one-to-many了,我們在BookType中這麼去設置
<set name="books" lazy="false" inverse="true" cascade="all">
<key column="col_booktype_id"></key>
<one-to-many class="hdu.management.library528.entity.Book"/>
</set>
我們一個個屬性來講解,這裏的set其實沒有對應數據庫的任何表和任何字段,首先這點大家要明確。
lazy 當設置爲true的時候——我們得到一個 歷史類 ,並沒有把這個類裏的書全部讀出來,而是當用的時候纔去讀
當設置爲false的時候,我們得到一個歷史類,裏面已經把books都封裝好了,全部讀出來了
很好理解吧?lazy就是懶惰的意思嘛。這裏有點需要注意,一般我們在用spring進行事務操作的時候,當lazy=“true”的時候很容易會出錯。解決辦法:
一、如果不考慮效率的話,大家可以乾脆把 lazy=“false”
二、可以去參考下 openSessionInView這個spring的攔截器
好了,我們講重點吧,首先來看cascade="all" 這個其實不用理解的很難,和many-to-one是一樣的,我們這麼理解,cascade是寫在哪個類裏的?答:booktype。它在對哪個類進行聲明?答:這裏是對book進行聲明。 好了,那麼意思就是,我們在刪除booktype和更新添加的時候,需不需要對book也進行操作的意思。
比如,在情況二中,我們是無法對booktype進行刪除的,因爲有外鍵關聯它,那麼在這裏我們設置了one-to-many後,OK了,當我們刪除booktype的時候,會先把相關的book全部刪除,接着把booktype給刪除。
最後講講重點 inverse="true" 我在剛剛接觸Hibernate的時候,對inverse、cascade這兩個東西最爲頭痛,現在cascade已經理解的非常清楚了吧?那麼我來總結inverse
第一、概念,指定要不要當自己來維護關係。(其實根本不用去理解)
第二、在one-to-many的時候,設置inverse=“true” 當然是在 one這個地方設置
第三、在many-to-many的時候,隨便在哪端先設置inverse=“true”,另一個地方設置inverse=“false”
第四、別問我:“那我不這麼設置行不行,換個方法設置下看看”,取消念頭,回到第二和第三條。
情況四
現在又有了新的要求,剛纔一直是 一個書本類下面有很多書,那麼在現實中,一本書它也有可能是屬於很多類別的,比如它既是歷史類的又是屬於地理類的。這個時候就要用many-to-many了。前面的關係中,我們用的是2張表來維護相互之間的關係,當多對多的時候,就需要在構建出一張表來維護了。
這裏我們構建出一個 書本——書本類 這樣一張表 ,裏面有2個字段,書本ID,書本類ID,在映射到Oracle中是自動轉換成聯合主鍵的,沒有重複。
* @hibernate.set table="lib_book_booktype" lazy="false" cascade="all" inverse="true"
*
* @hibernate.collection-key column="col_book_id"
* @hibernate.collection-many-to-many column="col_booktype_id" class="hdu.management.library528.entity.BookType"
*/
public Set getBookTypes() {
return bookTypes;
}
* @hibernate.set table="lib_book_booktype" lazy="false" cascade="all"
*
* @hibernate.collection-key column="col_booktype_id"
* @hibernate.collection-many-to-many column="col_book_id" class="hdu.management.library528.entity.Book"
*/
public Set getBooks() {
return books;
}
注意:不要忘記 private Set books = new HashSet();
設置和上面一樣,意思也一樣,唯一不同的就是多了個 table,column自然也要指向那個table了,這是設置之後,其實book和booktype這2張表圖了個安寧,什麼外鍵都沒有了,只是他們的關係表在控制它們兩個了。
我們繼續針對,在多對多中,inverse的問題,這裏我們把 book 的inverse=true booktype的inverse=false 當我們做這樣的操作時
book1.getBookTypes().add(bookType1);
book1.getBookTypes().add(bookType2);
book1.getBookTypes().add(bookType3);
bookService.saveOrUpdate(book1);
會發現 book1 保存了,bookType1、2、3也保存了,但是他們的關係卻沒有保存,爲什麼?因爲 book 把關係的inverse=true了,踢給別人去處理了,所以它不來理會關係的處理。所以,我們就要對 booktype這麼操作纔可以處理關係。當然如果,2端我們都去設置 inverse=false的話,都可以操作了,至於說效率方面的考慮,呵呵……先就不用管了。