新随笔  :: 订阅 订阅  :: 管理

[转]Hibernate中的cascade、inverse以及mappedBy总结

Posted on 2015-01-22 09:56  redcoatjk  阅读(398)  评论(0编辑  收藏  举报

有时, 相关知识只有经过动手才能融会贯通. 只有总结才能印象深刻. 

比如以下这篇blog总结的就很不错.

 

摘自http://blog.csdn.net/xiaozhubisheng/article/details/17021923

相关阅读: http://www.cnblogs.com/redcoatjk/p/4236445.html

     学习hibernate时对级联关系的概念老是分不清楚,尤其是cascade、inverse以及mappedBy的作用。下面通过例子来简单说明。

准备工作

    首先创建数据库,新建两张表:

   教室表cr,字段如下

 

     学生表student,字段如下:

 教室与学生是一对多的关系。

    然后新建项目,添加hibernate支持,由于inverse是hbm.xml配置文件中的属性,而mappedBy是注解中的属性,因此分开说明。

cascade属性

    cascade用于指示级联关系,即两个实体间存在级联关系(一个类是另一个类中的属性)时,当保存、更新或删除一个实体时,是否对关联的实体做出相应操作(数据库操作),例如

 1 <hibernate-mapping>
 2     <class name="model.Cr" table="cr" catalog="hbmtest">
 3         <id name="id" type="integer">
 4             <column name="id" />
 5             <generator class="identity" />
 6         </id>
 7         <property name="cname" type="string">
 8             <column name="cname" length="20" />
 9         </property>
10         <set name="students" inverse="true">
11             <key>
12                 <column name="crid" />
13             </key>
14             <one-to-many class="model.Student" />
15         </set>
16     </class>
17 </hibernate-mapping></SPAN>

上面是cr表的映射配置,执行如下测试代码

        Session session = HibernateSessionFactory.getSession();
        session.beginTransaction();
        Student stu = new Student();
        stu.setName("zhu");
        Cr cr = new Cr();
        cr.setCname("cname");
        Set<Student> set = new HashSet<Student>();
        set.add(stu);
        cr.setStudents(set);
        stu.setCr(cr);
        session.save(cr);
        session.getTransaction().commit();

执行上面代码后,数据表cr中插入一行,而student表未变化。而将上面的配置改为

<SPAN style="FONT-SIZE: 18px"><set name="students" cascade=<SPAN style="FONT-SIZE: 18px">"all" </SPAN>inverse="true">后,执行上述代码则<SPAN style="FONT-SIZE: 18px">student表会有<SPAN style="FONT-SIZE: 18px">数据插入。
</SPAN></SPAN></SPAN>

inverse

    inverse属性用于指示本方是否参与维护关系,设为true时不维护,设为false时维护。此处的关系是指关联两张表的

外键或者关系表字段。本属性一般设置于一对多关系中的一端,并且设置为false,因为若由一端负责维护,每次更新完一端数据,都会去寻找于一端有关系的多段表中的行,并更新其外键字段。而由多端维护时,由于一端对象是多端对象的属性字段,所以,每次更新多端后提交数据,都会自动更新该字段(若有更新时),这样比较方便。

<hibernate-mapping>
    <class name="model.Cr" table="cr" catalog="hbmtest">
        <id name="id" type="integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="cname" type="string">
            <column name="cname" length="20" />
        </property>
        <set name="students" cascade="all" inverse="true">
            <key>
                <column name="crid" />
            </key>
            <one-to-many class="model.Student" />
        </set>
    </class>
</hibernate-mapping>

执行以下测试代码:    

Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Student stu = new Student();
stu.setName("zhu");
Cr cr = new Cr();
cr.setCname("cname");
Set<Student> set = new HashSet<Student>();
set.add(stu);
cr.setStudents(set);
session.save(cr);
session.getTransaction().commit();

结果:

 

cr表

student表

由上图可以看出,由于cr不负责维护关系,所以插入一条cr数据后虽然在student插入一行,但其外键为null。当更改inverse为false或默认设置时,结果会更新student表的crid字段。

mappedBy

    mappedBy属性用于注解中,作用与inverse类似,不过其值必须为多端对象中对应一端对象的成员变量名。当设置后,由多端维护关系,未设置时,hibernate会去寻找由student的id字段和cr的id字段组成的关系表,如果未建立该表会报错。为了避免报错并且由两端同时维护关系,可以在一端加上@JoinColumn(name="多端外键字段名"),这样作用就等同于inverse=false了。

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="crid")
    public Set<Student> getStudents() {
        return this.students;
    }
        Session session = HibernateSessionFactory.getSession();
        session.beginTransaction();
        Student stu = new Student();
        stu.setName("zhu");
        Cr cr = new Cr();
        cr.setCname("cname");
        Set<Student> set = new HashSet<Student>();
        set.add(stu);
        cr.setStudents(set);
        session.save(cr);
        session.getTransaction().commit();

执行结果未两张表均插入一行,而且student表中的外键不为空。