存在的意义
在实际做项目的时候,经常会遇到表与表之间的关联操作,比如一个班级里面有多个学生,一个部门有多个职员,这是一对多的关系,还有例如一个主题有一个作者,这是一对一,等,这时候就必须涉及到表的关联操作
一对多的单项关联
什么意思呢?
比如一个班级里面有多个学生,班级表关联学生表,属于一对多,但是学生表并不关联班级表,这个就属于单项的关联
只能从classes找到student,所以为单项关联
class.hbm.xml中的配置
<set name="students" cascade="all" inverse="false">
<!--
用来描述外键
column 外键的名称
在hibernate低层拼接sql语句的时候,要用到外键
-->
<key>
<column name="cid"></column>
</key>
<!--
classes类与Student类之间的关系
-->
<one-to-many class="cn.itcast.sh08.hibernate.domain.Student"/>
</set>
而在student.hbm.xml中除了id和name属性以外没有有关class的属性设置
通过班级保存学生的级联操作
前提条件:
public void testSaveClasses_Cascade_Save_Student(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setName("java基础班");
/**
* 创建了一个set集合,往set集合中添加了3个学生
*/
Set<Student> students = new HashSet<Student>();
Student student = new Student();
student.setName("王三麻子");
Student student2 = new Student();
student2.setName("潘金莲");
Student student3 = new Student();
student3.setName("林志玲");
students.add(student);
students.add(student2);
students.add(student3);
//建立班级和学生之间的关联
classes.setStudents(students);
session.save(classes);
transaction.commit();
说明:
当执行session.flush的时候,通过第97行代码使classes变成持久化状态的对象,这个时候hibernate内部会去检查Classes.hbm.xml文件中的set元素,查看set元素上是否标有cascade属性,如果cascade属性的值为”save-update”,所以在保存classes的时候,检查classes对象中的set属性,这个时候set对象中有3个student对象,并且这三个student对象的主键没有值,所以在保存classes的时候同时保存了student。
保存班级的同时更新学生
在保存班级的同时更新学生也是同样的,上面的不变,执行的流程改变的就是在检查student的主键的值的时候发现是有值的,所以执行的是更新操作。
cascade属性(常用的)
上面已经提到了在更新班级或者新增班级的时候这个属性是必要要的,并且是save-update属性值,另外两个delete和all是干什么用的呢
public void testDeleteClasses(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class,2L);
session.delete(classes);
transaction.commit();
}
上述代码是在cascade=“save-update”的情况下执行的,如果cascade=“delete”或者是delete就会在删除班级的时候删除关联的学生
inverse属性
这个属性的值只有两种,true或者是false,默认的是true表示不维护属性,false表示维护属性,不维护属性的意思就是说在你删除班级的时候,就算cascade的属性值是delete,对应的学生是不会被删除的,因为关系不被维护,又比如说:
在新增学生的时候可以插入新的学生,但是学生没有对应的外键,也就是没有对应的班级,因为inverse不维护关系
级联和维护关系的区别
cascade是对象与对象之间的关系
inverse是对象与外键之间的关系,针对的是外键
总结
1、只能通过班级联系到学生,不能通过学生联系到班级
2、如果涉及到关系操作,只能从班级出发维护关系
3、只要涉及到维护关系就会发出update语句
4、所以一对多,一的一方维护关系效率不高
5、级联操作:save-update all delete
一对多的双向关联
其实跟一对多的单向关联差不多,只要你充分理解了单项关联,就基本理解双向,就像打架的时候,只不过是一种是只能一个人打另一个人,双向的就是两个人可以互相打,增加的部分:
在student.hbm.xml中
总结(效率的深入理解)
1、一对多如果多的一方维护关系,不会发出update语句
2、一般情况下,一对多,多的一方维护关系效率比较高
3、在一般情况下,classes.hbm.xml文件中的set元素中的inverse属性一般设置为true
4、如果上述的配置的inverse设置为false,那么只要更新了关系,只要在代码端建立了classes与student之间的关系,session只要操作classes,就会发出更新外键的sql语句,这样效率比较低
多对多
course.hbm.xml文件:
<class name="cn.itcast.sh08.hibernate.domain.Course">
<id name="cid">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<set name="students" table="student_course">
<!--
外键
-->
<key>
<column name="cid"></column>
</key>
<many-to-many class="cn.itcast.sh08.hibernate.domain.Student" column="sid"></many-to-many>
</set>
</class>
student.hbm.xml文件:
<class name="cn.itcast.sh08.hibernate.domain.Student">
<id name="sid">
<generator class="increment"></generator>
</id>
<property name="name" length="20"></property>
<!--
table属性代表第三张表
-->
<set name="courses" table="student_course" cascade="save-update">
<!--
外键
sid为student_course表中的一个外键
-->
<key>
<column name="sid"></column>
</key>
<!--
column
外键
-->
<many-to-many class="cn.itcast.sh08.hibernate.domain.Course" column="cid"></many-to-many>
</set>
</class>
持久化文件:
course的:
private Long cid;
private String name;
private Set<Student> students;
--------------------------------------------
student的:
private Long sid;
private String name;
private Set<Course> courses;
案例:
保存学生的同时保存课程
说明:
当执行session.flush的时候,hibernate内部的工作为:
1、保存学生
2、因为有cascade属性,所以要检查student中的set集合从而保存课程
3、因为inverse属性没有写,所以默认值为false,维护关系,所以要发出维护关系的sql语句
多对多的级联操作将会生成第三张表
删除课程
说明:
因为课程本身维护关系,所以在删除课程之间,hibernate内部会自动解除关系,然后再删除课程
总结
1、谁维护关系效率都一样
2、客户端的代码怎么写看发出的sql语句越少效率越高
3、关系的维护
建立关系:在第三张表中增加一行记录
解除关系:在第三张表中删除一行记录
重新建立关系:先删除后增加
一对一
一对一很简单,要注意的地方只有一个:
就是在<one-to-one>中需要有unique=“true” 并且还有column=“cid”表示cid在student表中是唯一的