搞定Hibernate表與表之間的關聯,搞懂cascade、inverse、lazy等屬性

2個類,書(Book),類別(BookType)

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的話,都可以操作了,至於說效率方面的考慮,呵呵……先就不用管了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章