`

cascade与inverse的使用

阅读更多
关于Hibernate中 cascade 与 inverse 的理解。


  今天在上课的时候,突然发现学员对上边的理解很不到位,所以就上网转载了该文章,希望学员有所收获。

    在学习Hibernate的过程中最不好理解的就是这两个属性了。

     据个例子:书上说inverse=false时,由主控方维持关系。。。
由于我也是初学者。。。再加上语文水平偏低。。。不理解“维持关系是啥意思”囧~

提示:
(1)如果:您不了解Hibernate的one-to-many或many-to-one的概念。

(2)如果:你不了解Hibernate的“自由态”“持久态”“游离态”的概念。

(3)如果:您不了解Hibernate中的“脏数据”的概念。

(4)如果:您对Hibernate中Session缓存,没有初步了解的话。
(在Hibernate中调用save进行存储数据的时候,并不是马上就对数据库进行insert操作,而是会将其“数据对象(vo)”纳入Hibernate的Session

缓存。)

在上面的4条提示中,如果您对其中的某一条,不是很清楚的话。希望请先了解有关知识。
否则,可能您将 “无法或很难”理解 cascade 或 inverse 这2个属性。

首相,cascade 与 inverse 这两个属性,其实是完全不同的两个东西,想要了解他们各自的“用途与区别”,详见如下介绍:

这里有两个表:

(1)class   (班级表)
相应字段:
cid    varchar(32) 主键 not-null (班级id)
cname varchar(16)      not-null (班级名称)  

(2)student (学生表)
相应字段:
sid    varchar(32) 主键 not-null (学生id)
sname varchar(16)      not-null (学生姓名)
class_id varchar(32)   not-null (学生所属班级)

一个班级(class)对应多个学生(student),所以班级表(class)就是“one-to-many”端
反之student就是many-to-one

//--------Class类的代码--------
public class Class implements.....
{
private cId = "";
private cName = "";
private students = java.util.HashMap();
// 省略对应的 geter setter
}
//--------Class.hbm.xml--------
<hibernate-mapping>
<class name="lcx.vo.Class" table="class"
   catalog="demo">
   <id name="cid" type="java.lang.String">
    <column name="cid" length="32" />
    <generator class="uuid.hex" />
   </id>
   <property name="name" type="java.lang.String">
    <column name="cname" length="16" not-null="true" />
   </property>
 
   <set name="students" table="student" cascade="save-update">
    <key column="class" />
    <one-to-many class="lcx.vo.Student" />
   </set>
</class>
</hibernate-mapping>

//--------Student类的代码;*******
public class Student implements.....
{
private sId = "";
private sName = "";
private Class class = null;
// 省略对应的 geter setter
}
// Student.hbm.xml
<hibernate-mapping>
<class name="lcx.vo.Student" table="student" catalog="demo">
   <id name="cid" type="java.lang.String">
    <column name="sid" length="32" />
    <generator class="uuid.hex" />
   </id>
   <many-to-one name="class"
    class="lcx.vo.Class"
    column="class_id"
    not-null="true"
   />  
</class>
</hibernate-mapping>

(一) cascade 的介绍:
当Hibernate持久化一个“临时对象(也叫自由态对象)”时,在默认的情况下(即:没有设置cascade属性或cascade=none时),Hibernate不会自

动“持久化他所关联”的其他临时对象。

上面这些话是什么意思呢? 什么叫不会自动 “持久化”关联的临时对象呢?

看如下代码:

// 创建一个 临时对象(也叫自由态对象)
// 也就是说这个 class 没有被Hibernate纳入Session缓存管理。
Class class = new Class();
//class.id 为自动生成
class.setName("一年级1班");

Student stu = new Student();
//student.id 为自动生成
stu.setName("小白兔");
stu.setClass(class);

// 关键就是这里。。。
class.getStudents().add(stu);

session.save(class);
// 提交

// 注意: Class.hbm.xml文件中,cascade="save-update"并且也没有设置inverse属性,也就是说inverse=false;
// 此时如果你开启了Hibernate的显示HQL语句功能,那么控制台将会显示如下3条HQL:

//----------------------------------------********
insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)
insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔,

66666666666666666666666666666666)
update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
//----------------------------------------********

那么为什么会出现,这3条HQL语句呢,我们来一一分析一下:

第1条HQL语句:
其实第一条HQL比较好理解,
当我们调用 session.save(class) 后,在Hibernate进行提交的时候,
会发现“有”一条“新”的数据要插入(insert),所以就往class表中,插入了这条新的class记录。

第2条HQL语句:
注意问题就在这里:
这里为什么又出现了一条insert语句呢?而且还是向student表中插入数据。
我们在上面的代码中,并没有编写类似“session.save(student)”这样的语句啊。
这是为什么呢?
其实原因,是这么回事:因为我们在class端,设置了"级联更新"(即:cascade="save-update"),
也就是说,当Hibernate在向class表中插入“新”对象记录时,会检查“Class对象”所关联的属性(就是<set>对应的属性),是否发生过变化

,如果发生了变化,就按照“级联属性(cascade)”所设定的内容
进行操作。

上面讲的这句话到底是什么意思呢?
用你们“人”话说,就是:
因为调用了 class.getStudents().add(stu);
所以,在Hibernate在进行插入 class对象的时候,发现class对象,所关联的集合中,有一条
“自由态”的对象,而又因为class端设置了“级联属性cascade”,所以,在插入这条 “新class对象”时,也一同把他内部的那些,还属于

“自由态”的其他对象,也一同插入到,他们所对应的表中去了。

还是不明白的话。。。可以看看。孙卫琴的《精通Hibernate》,在书上的第149页有。
但是关于inverse的介绍。。。写的就有些书面化了,如果语文不好的话。。。就难懂咯~

第3条HQL语句:
第三条HQL语句是一条update语句,是不是觉得,很莫名其妙。。。。
Hibernate大脑进水了吧,怎么吃饱了撑得,重复更新记录啊啊啊啊啊
假如:我们把 class端的配置文档中的 invser属性设置为true(即:inverse=true)
在执行上面的程序,发现,就变成2条insert语句啦。。。。。(update没啦。。。)
看来第三条的update语句和inverse有着密切的关系(他两有一腿~)。

所以我们下边,就来介绍一下inverse属性:

当调用 Class.getStudents().add(stu)方法,进行添加操作时,
(即:向 "这个Class对象"所属的“集合 (也就是调用getStudents方法所返回的那个Set集合)”中添加一个Student(即 add(stu)),也就是说

,这个“新”添加的Student对象(stu),
他的Student.class_id字段“必须”,要等于“被添加方Class”的主键(即:Class.cid)。
从“数据库”层面来讲,也就是说,这个“新”添加的“Student”的class_id字段,必须要与“Class”的cid字段,存在"主外键关联"。)

正因为如此:所以Hibernate“怕” 在进行 "Class.getStudents().add(stu)" 这样的操作时,
出现意外情况(如: stu.getClass=null,即:stu没有所属班级),
即“添加方”(Student)与“被添加方”(Class),存在“外键”不一致的情况发生。
所以就出现了 那条多余的update语句。即:one-to-many(Class端)主动去维护Child.Class_id
所以就是说,Hibernate怕出错,就给你多执行一次无用的更新语句,以保证 add 到 Class“集合”中的所有Student
都是要与Class有外键关联的。

用普通话说就是:
一年1班.getStudents().add(小白兔);
一年1班.getStudents().add(大白兔);

也就是说现在不管是 小白兔 还是 大白兔
如果他们,目前还没有自己的班级的话,
一年1班的班主任就会主动邀请他们成为一年1班的同学啦~。

也就是说 一年1班的班主任 主动邀请 同学,而不是 同学自己来~~~ 所以效率也降低了。。。。

所以我们一般把 一对多端 invser设置为true,即:不让主控端去维护主键关联,
(即:让同学自己去找班级)
说白了,就是,one-to-many端不用去管理 “新添加对象” 的主外键约束问题。

把one-to-many端(即:class端)的invser设置为true
(即:每次向class.getStudents这个集合中添加 student时,不去主动update对应的外键),
而是在student端去手动设置
例如:
student.setClass(class);
session.save(student);
这样手动设置 student与class关联啦。。。。
所以上面的程序“最好”还是写成这样:

Class class = new Class();
class.setName("一年级1班");
session.save(class);

Student stu = new Student();
stu.setName("小白兔");
stu.setClass(class);
session.save(class);

/*
此时向class集合add内容,不会进行数据库操作(update)。
“更新”的只是session缓存中,数据镜像。
这样做的好处是:不仅减少了update语句,
而且,同时也更新了session缓存。
------------------------
而在原来:
one-to-many端inverse=false时,虽然也更新seesion缓存中的class集合,
但是有却又多余update
*/
class.getStudents().add(stu);
// 提交

总结:
当inverse=false 并且向one-to-many端的关联集合,添加“新对象(即: 自由态对象)” 时,
Hibernate就会自动,去update那“个刚刚到来的” “自由态对象”的外键。
(如果你向,one-to-many端添的集合中,add一个“已经持久化了的对象”,那就不会出现update了(因为已经持久化过了),除非,你去 更改

“那个持久化对象”所对应的外键。。。那样的话。。。呵呵呵~~~
你可以试一试,应该不会报错,你可以当做练习去做一下,加深cascade和inverse这两个属性的理解)

// 如果看懂了上面的内容。来看一下,下面的东西。
假如,将one-to-many端(即:Class端)的 hbm.xml 文档中的cascade移除掉 或把cascade="none"。
那么上面的代码会出现什么情况呢。
结果会出现2条HQL,和一堆Exception
insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)
update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
Hibernate Exceptinon......................................

相比较cascade被设置"save-update"的时候,缺少了1条 insert语句,而且也多了一些Exception。

那么,到底是少了哪1条insert语句呢?
就是这条:
insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔,

66666666666666666666666666666666)

之所以会出现,这样的现象,想必您已经早就看出来了。
因为,我没有设置Class端的Cascade,所以在save(class)的时候,并没有自动将其所关联的“自由态对象”进行持久化操作。
然而,又因为 Class端的inverse=false,所以,Class会自动去维持,那个 “新来的student” 的外键。
所以会出现,没有insert就要update啦。。。。
然后在就是Exception了
分享到:
评论
1 楼 redcoatjk 2011-08-18  
写的很浅显易懂.
不错

相关推荐

    Hibernate中cascade与inverse属性详解

    Hibernate中cascade与inverse属性详解

    inverse和cascade使用阐述

    至于博文链接,虽然没有提供具体内容,但可以推测博主可能详细讲解了在特定工具或框架中如何配置和使用“inverse”和“cascade”,并可能给出了一些示例和最佳实践。 在压缩包文件“inverse_cascade”中,可能包含...

    关联映射cascade,inverse讲解

    本篇将深入讲解“cascade”和“inverse”这两个重要的概念,以及它们在实际应用中的作用。 首先,让我们理解一下“关联映射”。在Hibernate中,关联映射允许我们将Java对象与数据库表的记录进行关联。例如,一个...

    Hibernate中cascade和inverse应用

    在 Hibernate 框架中,`cascade` 和 `inverse` 是两个重要的概念,它们主要用于管理对象之间的持久化关系,特别是涉及到一对一(one-to-one)、一对多(one-to-many)和多对多(many-to-many)关系时。这两个属性都...

    hibernate 级联(cascade和inverse)一对多

    在Java的持久化框架Hibernate中,级联操作(Cascade)和反转(Inverse)是两个重要的概念,它们主要用于管理对象关系模型中的关联关系。在一对多的关系中,这些特性可以帮助简化数据操作,提高代码的可读性和维护性...

    关于cascade和inverse属性[文].pdf

    在软件网络技术领域,尤其是在使用Hibernate这种对象关系映射(ORM)框架时,理解和正确使用`cascade`和`inverse`属性至关重要。这两个属性主要用于管理对象之间的关联关系,特别是如何在数据库中维护这些关系。 ...

    hibernate inverse和cascade的详细讲解

    与`inverse`不同,`cascade`属性可以应用于所有涉及到关联的元素,如`&lt;many-to-one&gt;`、`&lt;one-to-one&gt;`、`&lt;any&gt;`、`&lt;set&gt;`、`&lt;bag&gt;`、`&lt;idbag&gt;`、`&lt;list&gt;`和`&lt;array&gt;`。 - **Cascade 的作用** - **定义**:`cascade...

    Hibernate_级联关系说明_-_关于cascade和inverse的用法

    在探讨Hibernate框架中的级联操作(cascade)与控制权反转(inverse)之前,我们需要先对Hibernate有一个基本的理解。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用提供了一种将对象模型映射到...

    NHibernate Inverse & Cascade

    "NHibernate Inverse & Cascade"是两个关键概念,对于理解和有效使用NHibernate至关重要。 **Inverse属性** Inverse属性主要用于控制NHibernate如何处理关联对象的持久化。在一对多或多对一的关系中,当一个实体...

    Hibenate cascade

    总之,理解和正确使用`cascade`和`inverse`属性对于优化Hibernate应用程序的性能和数据一致性至关重要。这两个属性的组合使用可以精确地控制对象关系的生命周期管理,确保数据库中的数据与程序中的对象状态保持一致...

    hibernate集合映射inverse和cascade详解.txt

    在深入探讨Hibernate集合映射中的`inverse`与`cascade`属性之前,我们首先需要理解Hibernate框架的基本概念。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用程序提供了一种将对象模型与数据库...

    Hibernate中Inverse和Cascade的区别.html

    Hibernate中Inverse和Cascade的区别.html

    inverse 例子

    在进行关联关系操作时,理解并合理使用`inverse`属性对于优化性能和保持数据一致性至关重要。在实际开发中,应根据业务需求和性能考虑来决定是否使用`inverse`以及如何设置。记住,良好的设计和合理的ORM配置是提高...

    JavaEE学习笔记之Hibernate表关系之一对多(inverse详解)

    2. **级联操作**:`inverse`属性常与`cascade`属性一起使用。`cascade`定义了关联实体的操作是否应级联到另一端。例如,`cascade="save-update"`意味着当父实体被保存或更新时,其关联的子实体也会随之保存或更新。...

    inverse=true的总结

    6. 工具应用:在实际开发中,理解并正确使用`inverse=true`能够提高代码的可维护性和性能。开发者应根据业务需求,谨慎选择关联的维护方,并合理配置级联操作,以达到最佳的数据操作效果。 总结,`inverse=true`是...

    hibernate_配置cascade_及all-delete-orphan.doc

    在使用Hibernate时,正确选择和配置cascade选项对于高效地管理和维护实体之间的关系至关重要。通过了解不同选项的特点和应用场景,开发人员可以更加灵活地应对各种业务需求,同时也能够有效地避免潜在的数据一致性...

    Hibernate开发租房系统2 源码

    描述提到“使用cascade和inverse优化区和街道关联关系”,这意味着我们将深入理解Hibernate的cascade和inverse属性,以及它们在双向一对多关联关系中的应用。 Hibernate是Java领域中广泛使用的对象关系映射(ORM)...

    Hibernate常见问题

    理解并正确使用Hibernate的`cascade`和`inverse`属性对于优化数据操作和避免数据一致性问题至关重要。在实际开发中,应根据业务逻辑和数据模型谨慎设定这些属性,以确保数据操作的正确性和高效性。

Global site tag (gtag.js) - Google Analytics