1、cascade属性和inverse属性的作用是什么,即为什么要用他们?
2、在什么情况下使用他们?
3、如何使用他们?
对于hibernate的实体对象的配置,可能时常会用上它们,所以必须将其弄清楚明白,
于是自己通过网上查找资料以及编写实例进行了大量 测试后,解决问题。
inverse和cascade的比较
这两个属性本身互不影响,但起的作用有些类似,都能引发关系表的更新。
inverse:
在映射一对多关系时,设为false(默认false),一的一方会维护两者之间的关系,设为true后,一的一方不会维护两者之间的关系。四个字概括——关联更新。
作用:不使用它时(即默认false),对一的一方的数据操作(增加、更新、删除),如果改动了 set 集合,为了维护与多的一方的关系,hibernate会额外增加一条update语句,更新多的一方相关联字段,这样就降低了执行效率,额外消耗了性能。
inverse=true的作用就是:不管一的一方做怎样的数据操作,都不会反映到另一方,不会触发相应的update操作。
配置范围:只能配置在one-to-many,many-to-many的set标签上,一对多映射中一的一方。
示例1:one-to-many时。
学生(Student)与班级(ClassInfo)的关系,学生多的一方,班级一的一方
班级映射文件 ClassInfo.hbm.xml 配置如下(默认的情况下):
<set name="students">
<key column="classId"/>
<one-to-many class="Student"/>
</set>
插入操作的代码:
Student student = new Student();
student.setName("张三");
ClassInfo classInfo = new ClassInfo();
classInfo.setName("重点班");
classInfo.getStudents().add(student); //此行代码表示,由班级一方主控操作
session.save(student);
session.save(classInfo);
生成sql语句:
Hibernate:
insert
into
tb_student
(name, cardId, classId, id)
values
(?, ?, ?, ?)
Hibernate:
insert
into
tb_classInfo
(name, id)
values
(?, ?)
Hibernate:
update
tb_student
set
classId=?
where
id=?
由此可见:每增加一个学生,额外生成了一条update语句。
数据库中数据如下:
tb_classInfo: id name
1 重点班
tb_student: id name classId
1 张三 1
如果将ClassInfo.hbm.xml 配置如下,其它不变:
<!-- 设置inverse为true -->
<set name="students" inverse="true">
<key column="classId"/>
<one-to-many class="Student"/>
</set>
执行同样插入操作后,
生成sql语句:
Hibernate:
insert
into
tb_student
(name, cardId, classId, id)
values
(?, ?, ?, ?)
Hibernate:
insert
into
tb_classInfo
(name, id)
values
(?, ?)
可见,无更新语句了。
数据库中数据如下:
tb_classInfo: id name
1 重点班
tb_student: id name classId
1 张三 null
表tb_student中字段classId为空,说明对班级的插入操作,没有维护与其对应的学生的关系。
示例2:many-to-many时。
学生(Student)和所修课程(Course),多对多的关系
多对多的关系是,两者会维护一张中间表,tb_student_course,
此时,学生表和课程表相对于此中间表,都是一对多关系
Student.hbm.xml 配置如下:
<set name="courses" table="tb_student_course" >
<key column="studentId"/>
<many-to-many class="Course" column="courseId"/>
</set>
插入操作的代码:
Student student = new Student();
student.setName("李四");
Course course = new Course();
course.setName("外语");
student.getCourses().add(course); //由学生主控插入操作
session.save(course);
session.save(student);
生成sql语句:
Hibernate:
insert
into
tb_course
(name, id)
values
(?, ?)
Hibernate:
insert
into
tb_student
(name, cardId, classId, id)
values
(?, ?, ?, ?)
Hibernate:
insert
into
tb_student_course
(studentId, courseId)
values
(?, ?)
由此可见:每增加一个学生与课程信息,在往数据库中insert学生信息和课程信息后,
还会往它们维护的中间表tb_student_course中insert数据,此数据作用就是维护它们的关系。
数据库中数据如下:
tb_student: id name
1 李四
tb_course: id name
1 外语
tb_student_course: studentId courseId
1 1
如果将Student.hbm.xml 配置修改如下,其它不变:
<!-- 设置inverse为true -->
<set name="courses" table="tb_student_course" inverse="true" >
<key column="studentId"/>
<many-to-many class="Course" column="courseId"/>
</set>
执行同样插入操作后,
生成sql语句:
Hibernate:
insert
into
tb_course
(name, id)
values
(?, ?)
Hibernate:
insert
into
tb_student
(name, cardId, classId, id)
values
(?, ?, ?, ?)
可见,只有两条insert语句。
数据库中数据如下:
tb_student: id name
1 李四
tb_course: id name
1 外语
tb_student_course: studentId courseId
此表无数据
由此可得出结论:
- 对于数据插入的操作,inverse决定是否把对 set 的改动反映到数据库中,即是否产生update语句。
- one-to-many下,对于数据更新和删除的操作,也同数据的插入操作一样(在此就不具体演示了),当inverse=false时(默认时),对 set 集合的改动会产生update语句去更新对应的多的一方的数据。当inverse=true时,对 set 集合的改动不会产生update语句去更新对应的多的一方的数据。即放弃维护两者关系的权利。
- many-to-many时,其实也可看成是one-to-many的特殊形式,student和course共同维护一个中间表tb_student_course。student表或course表对中间tb_student_course来说,都是一对多的关系,所以不管是student还是course,改变 set ,只更新中间表的数据,不会影响另一方。
- 建议,一对多的映射配置,一般不让一的一方维护关系,会损耗性能,让多的一方去维护。所以一的一方的配置属性inverse=true。 但多对多情况时,一定让inverse=false。
删除操作示例:
// 删除一个班级。
// inverse=false时,先更新相关联的student表的外键classId设为null,再删此班级
// inverse=true时,不会更新student表classId字段,直接删班级会由于两者的外键约束,无法删除,报异常。
ClassInfo classInfo = (ClassInfo)session.get(ClassInfo.class, 1);
session.delete(classInfo);
cascade:
级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
作用:一个对象的操作,可以因级联而触发跟它相关联的所有对象的操作,由此简化了代码。
配置范围:只有“关系标记”才有cascade属性:many-to-one,one-to-one ,any ,set(map, bag, idbag, list, array) ,one-to-many(many-to-many)
假设三个对象: student(学生)、classInfo(班级)、course(课程)
student(多)----------> classInfo(一)
student(多)----------> course(多)
当我执行保存学生对象操作时:
session.save(student) 级联决定是否执行:save_or_update(classInfo)、 save_or_update(course)
当我执行更新学生对象操作时:
session.update(student) 级联决定是否执行: save_or_update(classInfo) 、save_or_update(course)
当我执行删除学生对象操作时:
session.delete(student) 级联决定是否执行: session.delete(classInfo) 、session.delete(course)
注意:save或者update的主控操作因级联引发的关联操作可能为save,也可能为update,hibernate会根据关联对象是否已存在于数据库中而决定是save还是update。
建议:cascade,一般对many-to-one,many-to-many,constrained=true的one-to-one 不设置级联删除
在many-to-many下,cascade影响到的是另一方,而inverse影响的是中间表。