最近发现许多人谈到博客可以巩固和提高自己的学习.所以决定在此发表一些自己的看法.
这里我想谈下自己对inverse和cascade使用.使用Hibernate一段时间了.总觉得自己对cascade和inverse的只是一点认识.这里进行简单的测试总结:
我使用了Classes和Student这2个一对多的关系进行测试.使用的环境是Junit4和Hibernate3.2.IDE使用Eclipse.
下面是Class的xml配置:
<hibernate-mapping
package="com.entity">
<class name="Classes" table="tb_class">
<id name="id">
<generator class="native"></generator>
</id>
<property name="number"></property>
<!--
在这里进行关系的设置
大写的部分inverse="true"表示 Classes 本身不维护表之间的关系!,而由想反的一方 student来维护,
cascade="all"表示 无论是update,insert ,delete 都保持几连关系
lazy="true"表示初始化课室的时候不会把所有的学生都从数据库中load进来。
-->
<set name="students" inverse="true" cascade="all" lazy="true">
<key>
<column name="class_id"></column>
</key>
<one-to-many class="Student"/>
</set>
</class>
下面是测试的代码:
情况1:
System.out.println("cascade='all' inverse='true'主控方为Student.多的那一方");
Session session = sf.openSession();
Classes classes = new Classes();
classes.setNumber("s1");
System.out.println("Class建立关系");
Student student = new Student();
classes.getStudents().add(student);
session.save(classes);
session.beginTransaction().commit();
session.close();
Session session1 = sf.openSession();
classes.setNumber("s1");
System.out.println("Student建立关系");
Student student1 = new Student();
student1.setClasses(classes);
session1.save(student1);
session1.beginTransaction().commit();
输出的结果为:
cascade='all' inverse='true'主控方为Student.多的那一方
Classes建立关系
Hibernate: insert into tb_class (number) values (?)
//数据库语句发出但是tb_student表中的数据没有与Classes建立关系.外键设置为空
//这里证明了如果学生维护关系的话.只往课室加学生的话使用session.save的话将不会
//保存学生.
Hibernate: insert into tb_student (name, class_id) values (?, ?)
Student建立关系
//只能在存在课室之后再添加学生才能形成学生和课室的关系
Hibernate: insert into tb_student (name, class_id) values (?, ?)
情况2:
System.out.println("cascade='all' inverse='false'主控方为Classes.一的那一方");
Session session = sf.openSession();
System.out.println("Classes建立关系");
Classes classes = new Classes();
classes.setNumber("s1");
Student student = new Student();
classes.getStudents().add(student);
session.save(classes);
session.beginTransaction().commit();
System.out.println("Class存在情况下.Student建立关系");
Session session1 = sf.openSession();
Student student1 = new Student();
student1.setClasses(classes);
session1.save(student1);
session1.beginTransaction().commit();
System.out.println("Class不存在情况下Student建立关系");
Session session2 = sf.openSession();
Classes classes2 = new Classes();
classes2.setNumber("s1");
Student student2 = new Student();
student2.setClasses(classes2);
session2.save(student2);
session2.beginTransaction().commit();
测试输出的结果为:
Classes建立关系
Hibernate: insert into tb_class (number) values (?)
Hibernate: insert into tb_student (name, class_id) values (?, ?)
//明显比原来多了一句.这里每次学生都需要更新教室的id这速度将会减慢.
//在教室中有学生的集合.它自己无法判断哪个学生已经指向自己了.只能再有这学生的时候
//将这个教室号赋予给它.所以在这个学生与课室这个场景下应该设置学生来维护这个关系.
//当学生需要进入这个教室的时候才进行选择这是可以减轻数据库的负担.(一般的场景下.一对多都是多的一方维护关系比较多.)
Hibernate: update tb_student set class_id=? where id=?
Class存在情况下.Student建立关系
Hibernate: insert into tb_student (name, class_id) values (?, ?)
Class不存在情况下Student建立关系
Hibernate: insert into tb_student (name, class_id) values (?, ?)
//学生无法进入这个教室而在这教室还没建成之前
org.hibernate.TranientObjectException
情况3:
System.out.println("cascade没有设置 inverse='false'主控方为Classes.一的那一方");
System.out.println("Classes建立关系");
Session session = sf.openSession();
Classes classes = new Classes();
classes.setNumber("s1");
Student student = new Student();
classes.getStudents().add(student);
session.save(classes);
session.beginTransaction().commit();
测试输出结果:
Hibernate: insert into tb_class (number) values (?)
Hibernate: update tb_student set stu_id=? where id=?
//从下面异常可以看到.inverse定义的是关系和对象的级联关系。教室这里负责与学生建
//立关系.但是这时候出现的情况是并不存在这个学生.那就肯定报错了.
//也可以看出cascade定义的是关系两端对象到对象的级联关系
org.hibernate.TranientObjectException:object references an unsaved
transient instance - save the transient instance before flushing: com.entity.Student
与情况2的对比可以看出
cascade:在对主控方操作时,级联发生。
inverse: 在flush时(commit会自动执行flush),对session中的所有set,hibernate判断每个set是否有变化,
对有变化的set执行相应的sql,执行之前,会有个判断:if( inverse == true ) return;
可以看出cascade在先,inverse在后。
情况4
System.out.println("cascade没有设置 inverse='true'主控方为Student.多的那一方");
Session session = sf.openSession();
Classes classes = new Classes();
classes.setNumber("s1");
Student student = new Student();
classes.getStudents().add(student);
session.save(classes);
session.beginTransaction().commit();
测试输出结果:
//这里因为2个级联关系都不存在.所以只是普通的添加
Hibernate: insert into tb_class (number) values (?)
下面是我测试的源码.由于jar包比较大就只传代码