现在的位置: 首页 > 综合 > 正文

搞定Hibernate表与表之间的关联,搞懂cascade、inverse、lazy等属性

2018年05月21日 ⁄ 综合 ⁄ 共 3834字 ⁄ 字号 评论关闭
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的话,都可以操作了,至于说效率方面的考虑,呵呵……先就不用管了。

抱歉!评论已关闭.