级联操作
1、只能通过班级联系到学生,不能通过学生联系到班级
2、如果涉及到关系操作,只能从班级出发维护关系
3、只要涉及到维护关系就会发出update语句
4、所以一对多,一对一方维护关系效率不高
5、级联操作:save-update
一对多的情况
结构
public class Student implements Serializable{
private Long sid;
private String name;
private Classes classes;
在Student.hbm.xml文件中
<many-to-one name="classes" class="cn.itcast.sh08.hibernate.domain.Classes" column="cid"></many-to-one>
保存学生,并且建立和班级的关系
@Test
public void testSaveStudent(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
/**
* 新创建一个学生
*/
Student student = new Student();//临时状态的对象
student.setName("adsf");
//提取cid为7的班级
Classes classes = (Classes)session.get(Classes.class,7L);
student.setClasses(classes);
session.save(student);
transaction.commit();
}
学生转移班级
@Test
public void testTransform(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class, 3L);
Student student = (Student)session.get(Student.class, 1L);
student.setClasses(classes);
transaction.commit();
}
保存一些学生,建立关系
@Test
public void testSaveStudent_R(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student1 = new Student();
student1.setName("aaa");
Student student2 = new Student();
student2.setName("bbb");
Classes classes=(Classes)session.get(Classes.class, 3L);
student1.setClasses(classes);
student2.setClasses(classes);
session.save(student1);
session.save(student2);
transaction.commit();
}
1、一对多如果多的一方维护关系,不会发出update语句
2、一般情况下,一对多,多的一方维护关系效率比较高
3、在一般情况下,classes.hbm.xml文件中的set元素中的inverse属性一般设置为true
4、如果上述的配置的inverse设置为false,那么只要更新了关系,只要在代码端建立了classes与student之间的关系,session只要操作classes,就会发出更新外键的sql语句,这样效率比较低
多对多
持久化类和映射文件
public class Course implements Serializable{
private Long cid;
private String name;
private Set<Student> students;
public class Student implements Serializable{
private Long sid;
private String name;
private Set<Course> courses;
在Student.hbm.xml文件中
<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>
在Course.hbm.xml文件中
<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>
考虑问题
1、多对多谁维护关系效率比较高
谁维护关系,都得修改第三张表,所以谁维护关系效率都一样。
2、关于关系:
a)当建立关系的时候,相当于插入一行数据
b)当解除关系的时候,相当于删除一行数据
c)当重新建立关系的时候,先删除后增加
/**
* 保存学生的同时保存课程
*/
@Test
public void testSaveStudent_Cascade_Save_Course(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
/**
* 新建一个学生
*/
Student student = new Student();
student.setName("aa");
/**
* 新建一个课程
*/
Course course = new Course();
course.setName("java基础");
/**
* 建立学生和课程之间的关系
*/
Set<Course> courses = new HashSet<Course>();
courses.add(course);
student.setCourses(courses);
session.save(student);
transaction.commit();
}
说明:
当执行session.flush的时候,hibernate内部的工作为:
1、保存学生
2、因为有cascade属性,所以要检查student中的set集合从而保存课程。
因为inverse属性没有写,所以默认值为false,维护关系,所以要发出维护关系的sql语句。
/**
* 已知一个课程,已知一个学生,建立该学生和该课程之间的关系
* 建立sid为2的学生和cid为1的课程之间的关系
*/
@Test
public void testBuildR(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//提取sid为2的学生
Student student = (Student)session.get(Student.class, 2L);
//提取cid为1的课程
Course course = (Course)session.get(Course.class, 1L);
student.getCourses().add(course);//获取到sid为2的所有的课程,在此基础上加一门课程
//course.getStudents().add(student);
transaction.commit();
}
/**
* 一个学生从一个课程转移到另外一个课程
* 学生1从课程1转移到课程2
*/
@Test
public void testTransform(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//获取学生1,课程1,课程2
Student student = (Student)session.get(Student.class, 1L);
Course course1 = (Course)session.get(Course.class, 1L);
Course course2 = (Course)session.get(Course.class, 2L);
student.getCourses().remove(course1);//解除该学生与课程1之间的关系 删除关系的操作
student.getCourses().add(course2);//建立该学生与课程2之间的关系 增加关系的操作
transaction.commit();
}
/**
* 解除一个课程和该课程所有的学生之间的关系
* 解除cid为2的课程和该课程所有的学生之间的关系
*/
@Test
public void testRelease_R(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
//获取cid为2的课程
Course course = (Course)session.get(Course.class, 2L);
//把课程中的学生设置为null
course.setStudents(null);
transaction.commit();
}
/**
* 删除一个课程
*/
@Test
public void testDeleteCourse(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Course course = (Course)session.get(Course.class, 1L);
session.delete(course);
transaction.commit();
}
总结
1、谁维护关系效率都一样
2、客户端的代码怎么写看发出的sql语句越少效率越高
3、关系的维护
建立关系:在第三张表中增加一行记录
解除关系:在第三张表中删除一行记录
重新建立关系:先删除后增加
一对一
在Student.hbm.xml文件中
<many-to-one name="classes" unique="true" column="cid"></many-to-one>
说明cid在student表中的值是唯一的
懒加载(延迟加载)
用到该数据的时候才要向数据库要数据
类的延迟加载
/**
* 类的延迟加载
*/
@Test
public void testClassLazy(){
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.load(Classes.class,1L);
//System.out.println(classes.getName());
transaction.commit();
}
说明:
由session.load方法产生的classes为代理对象,似乎由javasist包产生的,属性为null。
上述的代码并不发出sql语句当执行输出语句时才要发出sql语句
Classes.hbm.xml文件中进行如下的设置:
<class name="zx.hibernate.domain.Classes" lazy="true">
/**
* 集合的延迟加载
*/
@Test
public void testSetLazy(){
/**
* 加载cid为1的班级的所有的学生
*/
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class, 1L);
Set<Student> students = classes.getStudents();
for(Student student:students){
System.out.println(student.getName());
}
transaction.commit();
}
说明:在for循环的时候才发出加载集合的sql语句,这样的情况为集合的延迟加载
如果把set集合的延迟加载变成false,则在加载classes的时候,同时加载student
/**
* 集合的延迟加载Extra
*/
@Test
public void testSetLazy_Extra(){
/**
* 加载cid为1的班级的所有的学生
*/
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes)session.get(Classes.class, 1L);
Set<Student> students = classes.getStudents();
System.out.println(students.size());
transaction.commit();
}
因为把lazy设置成了extra,在客户端的代码只需要学生的数量,所以只发生了count的sql语句,为更进一步的延迟加载
Manytoone的延迟加载
说明:
默认值为no-proxy,为延迟加载。但是多对一的延迟加载对于效率的提高有限,因为根据多的一方加载一的一方就加载一个对象,所以保持默认就好。
总结
1、懒加载是通过控制sql语句的发出时间来提高效率的
2、但映射文件只有一份,不能随便改
3、懒加载只不过是hibernate给程序员提供的一种优化途径而已