Inverse和cascade是Hibernate映射中最难掌握的两个属性。两者都在对象的关联操作中发挥作用。
1.明确inverse和cascade的作用
inverse 决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因 为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。
cascade决定是否把对对象的改动反映到数据库中,所以cascade对所有的关联关系都起作用(因为关联关系就是指对象之间的关联关系)。
2.inverse属性 :inverse所描述的是对象之间关联关系的维护方式。
inverse只存在于集合标记的元素中 。Hibernate提供的集合元素包括<set/> <map/> <list/> <array /> <bag />
Inverse属性的作用是:是否将对集合对象的修改反映到数据库中。
inverse属性的默认值为false,表示对集合对象的修改会被反映到数据库中;inverse=false 的为主动方,由主动方负责维护关联关系。
inverse=”true” 表示对集合对象的修改不会被反映到数据库中。
为了维持两个实体类(表)的关系,而添加的一些属性,该属性可能在两个实体类(表)或者在一个独立的表里面,这个要看这双方直接的对应关系了: 这里的维护指的是当主控放进行增删改查操作时,会同时对关联关系进行对应的更新。
一对多: 该属性在多的一方。应该在一方的设置 inverse=true ,多的一方设置 inverse=false(多的一方也可以不设置inverse属性,因为默认值是false),这说明关联关系由多的一方来维护。如果要一方维护关 系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。而如果让"多"方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。显然这样做的话,会减少很多操作,提高了效率。
注:
单向one-to-many关联关系中,不可以设置inverse="true",因为被控方的映射文件中没有主控方的信息。
多对多: 属性在独立表中。inverse属性的默认值为false。在多对多关联关系中,关系的两端 inverse不能都设为false,即默认的情况是不对的,如果都设为false,在做插入操作时会导致在关系表中插入两次关系。也不能都设为 true,如果都设为true,任何操作都不会触发对关系表的操作。因此在任意一方设置inverse=true,另一方inverse=false。
一对一: 其实是一对多的一个特例,inverse 的设置也是一样的,主要还是看关联关系的属性在哪一方,这一方的inverse=false。
多对一: 也就是一对多的反过来,没什么区别。
=--------------------------------------------------------------------------------------
inverse常用于一对多双向关联关系中。以Student(学生)和Class(班级)为例,它们之间的关系为一对多的关系,即一个学生只能属于一个班级,一个班级可以包含多个学生。学生类定义代码:Class Student{ private int id; private String name; private Class class; //省略getter()和setter()方法}班级类定义代码:Class Class{ private int id; private String name; private Set students = new HashSet(); //省略getter()和setter()方法}Student类的映射文件:<class name="Student" table="STUDENT"> <id name="id" type="int" column="ID"> <generator class="native" /> </id> <property name="name" type="string" column="NAME" /> <many-to-one name="class" column="CLASS_ID" class="Class" cascade="save-update" /> </class>Class类的映射文件:<class name="Class" table="CLASS"> <id name="id" type="int" column="ID"> <generator class="native" /> </id> <property name="name" type="string" column="NAME" /> <set name="students" table="STUDENT" cascade="save-update" inverse="false"> <key column="CLASS_ID" /> <one-to-many class="Student" /> </set></class>希望你能对这两个映射文件所表达的数据库模式有正确的认识。即STUDENT表中存在一个名为CLASS_ID的字段,它和CLASS表中的ID字段是主外键关系。那个inverse属性就是用来规定是由谁(Student或Class)来维护这个主外键关系的。inverse的默认值为false。在处理逻辑代码中,如下:Class c1 = new Class();c1.setName("一班");Student s1 = new Student();Student s2 = new Student();s1.setName("Jason");s2.setName("Tom");c1.getStudents().add(s1);c2.getStudents().add(s2);s1.setClass(c1);s2.setClass(c1); //注释1session.save(c1);上面的代码会使Hibernate执行五条SQL语句,其中前三条是insert插入语句,后两条是update更新语句。插入就不用说了,那么为什么还要有更新语句呢?这是因为Class类映射文件的<set>元素中指定了inverse="false",这就告之Hibernate:STUDENT表与CLASS表的主外键关系是由Class类来维护的。当执行save后,执行了三条insert语句,这三条语句中的后两条是插入到STUDENT表的,它们的CLASS_ID字段是通过s1.getClass().getID()取出的,假如我将上面“注释1”处修改为s2.setClass(c2);(c2是另一个Class对象,可能是持久化对象),这样,主外键关系不就乱了吗。为了保证主外键关系,Hibernate在这种情况下会再执行两条update语句来更改STUDENT表中两个新插入记录的CLASS_ID字段,当然,这时CLASS_ID字段的取值是从c1对象中直接取得,而不再是s1.getClass().getID()方式了。如果我们将Class类映射文件的<set>元素中的inverse属性修改为true,这就是告诉Hibernate:Class类不维护主外键关系了,这个任务就交给了Student类。于是,我们再执行上面的代码,Hibernate就会只执行三条insert语句,而不会执行任何update语句。因为Hibernate会通过Student类的s1.getClass().getID()和s2.getClass().getID()来确定CLASS_ID字段的值。故,为了节省数据库资源,省却不必要的update语句,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。打个比方:在一个公司中,是老板认识所有的员工容易,还是所有员工认识老板容易?我是一个Hibernate的初学者,前两天刚刚研究了一下inverse属性,有所心得。写了这么多东西,希望能对你有所帮助。
=--------------------------------------------------------------------------------------
2.cascade属性
cascade属性的作用是描述关联对象进行操作时的级联特性。因此,只有涉及到关系的元素才有cascade属性。
具 有cascade属性的标记包括<many-to-one /> <one-to-one /> <any /> <set /><bag /> <idbag /> <list /> <array />
注意:<ont-to-many />和 <many-to-many />是用在集合标记内部的,所以是不需要cascade属性的。
级联操作:指当主控方执行某项操作时,是否要对被关联方也执行相同的操作。
3.inverse和cascade的区别
作用的范围不同:
Inverse是设置在集合元素中的。
Cascade对于所有涉及到关联的元素都有效。
<many-to-one/><ont-to-many/>没有inverse属性,但有cascade属性
执行的策略不同
Inverse 会首先判断集合的变化情况,然后针对变化执行相应的处理。
Cascade 是直接对集合中每个元素执行相应的处理
执行的时机不同
Inverse是在执行SQL语句之前判断是否要执行该SQL语句
Cascade则在主控方发生操作时用来判断是否要进行级联操作
执行的目标不同
Inverse对于<ont-to-many>和<many-to-many>处理方式不相同。
对于<ont-to-many>,inverse所处理的是对被关联表进行修改操作。
对于<many-to-many>,inverse所处理的则是中间关联表
Cascade不会区分这两种关系的差别,所做的操作都是针对被关联的对象。
总结:
<one-to-many>中,建议inverse=”true”,由“many”方来进行关联关系的维护
<many-to-many>中,只设置其中一方inverse=”false”,或双方都不设置
Cascade,通常情况下都不会使用。特别是删除,一定要慎重。
操作建议
一般对many-to-one和many-to-many不设置级联,这要看业务逻辑的需要;对one-to-one和one-to-many设置级联。
many-to-many关联关系中,一端设置inverse=”false”,另一端设置为inverse=”true”。在one-to-many关联关系中,设置inverse=”true”,由多端来维护关系表