【Hibernate】详解Hibernate中的inverse=”true”

首先两个类,一个是班级类,一个是学生类:

public class Grade{ 
     private int id; 
     private String name;
     private Set students = new HashSet();
}

public class Student { 
     private int id; 
     private String studentName;
}

数据库中表的结构: 

t_grade: 两个字段:id  name

t_student: 三个字段:id  studentName  gradeid


Grade类的映射文件:Grade.hbm.xml(此时是单向关联)

<hibernate-mapping>
<class name="Grade" table="t_grade" lazy="false">  
		<id name="id"> 
		   <generator class="native"/>
		</id>  
		<property name="name"/>  
		<strong><set name="students"  cascade="save-update"  lazy="false">
		   <key column=" gradeid "/>
		   <one-to-many class="Student"/>
		</set></strong>
</class> 
</hibernate-mapping>

现在执行以下java代码:

Set students = new HashSet(); 
			
Student s1 = new Student ();
s1.setStudentName("s1"); 
Student o2 = new Student();
s2.setStudentName ("s2");	 
students.add(s1);
students.add(s2);  	
			
Grade g = new Grade();
g.setName("g1");
g1.setStudents(students);  

session.save(c);

此时Hibernate发出的sql语句如下: 

Hibernate: insert into t_grade (name) values (?)
Hibernate: insert into t_student (studentName) values (?)
Hibernate: insert into t_student (studentName) values (?)
Hibernate: update t_student set gradeid=? where id=?
Hibernate: update t_student set gradeid =? where id=?

此时查询数据库,显示如下:

t_grade:

id   |  name

1          g1

 

t_student:

id   |  studentName   |   gradeid

1            s1                         1

2            s2                         2


在保存Grade对象时,会先发出insert into t_grade(name) values (?)语句将g1同步到数据库中,因为在<set>映射中设置了cascade=”save-update”,所以会同时保存s1、s2两个对象。如果在映射文件中没有设置cascade=”save-update”的话,那么Hibernate就不会自动保存students集合对象,那在更新时将抛出异常:

Hibernate: insert into t_grade (name) values (?)
Hibernate: update t_student set gradeid=? where id=?
org.hibernate.TransientObjectException: Student

异常分析:

    因为在<set>的inverse属性中默认是“inverse=false”,就是由Grade对象当主控方,由它负责关联关系的维护,也就是负责更新t_student表中的gradeid,但是因为没有设置casade=”save-update”,所以students集合中的对象不会在保存grade时自动保存,所以会抛出异常。


重新设置casade=”save-update”,并且设置inverse=”true”,如下: 
<set name="students" cascade="save-update" inverse="true" lazy="false">
	<key column="gradeid"/>
	<one-to-many class="Student "/>
</set> 

同样执行上述java代码,hibernate发出的语句如下:

Hibernate: insert into t_grade (name) values (?)
Hibernate: insert into t_student (studentName) values (?)
Hibernate: insert into t_student (studentName) values (?)

此时查看数据库,显示如下:

t_grade:

id   |  name

1          g1

 

t_student:

id   |  studentName   |   gradeid

1            s1                      NULL

2            s2                      NULL

这时t_student表的gradeid为NULL,因为设置了inverse=”true”,所以此时Student是主控方,关联关系的维护由Student来完成,在保存Grade对象时,grade不会再维护Students的gradeid属性,必须由student自己来维护,也就是说必须要设置student.setGrade(grade);

 

当通过Student来维护关联关系时,那么这个关联关系就转换成了双向关联

在Student类中添加一行代码,变成如下:

public class Student { 
private int id; 
private String studentName;
private Grade grade;
}

此时Student.hbm.xml也要增加几行代码:

<hibernate-mapping>
<class name="Student" table="t_student">  
		<id name="id"> 
		   <generator class="native"/>
		</id>  
		<property name="studentName"/> 
		<many-to-one name="grade" column="gradeid"/>
</class> 
</hibernate-mapping>

此时如果再执行之前的java代码,hibernate发出如下语句:

Hibernate: insert into t_grade (name) values (?)
Hibernate: insert into t_student (studentName,gradeid) values (?, ?)
Hibernate: insert into t_student (studentName,gradeid) values (?, ?)

此时保存Student对象会为gradeid赋值,因为Student对象中拥有Grade属性,对应gradeid字段,此时查看数据库,还是和之前的一样:

t_grade:

id   |  name

1          g1

 

t_student:

id   |  studentName   |   gradeid

1            s1                      NULL

2            s2                      NULL

Gradeid的值还是为NULL的原因是因为上面的java代码中没有设置Student对象的Grade属性,由于我们设置了inverse=”true”,就变为由Student对象维护关联关系,所以必须在java代码中加多一行student.setGrade(grade);

修改代码为:

Grade g = new Grade();
Set students = new HashSet(); 
			
Student s1 = new Student ();
s1.setStudentName("s1"); 
s1.setGrade(g);
Student o2 = new Student();
s2.setStudentName ("s2");	
s2.setGrade(g); 
students.add(s1);
students.add(s2);  	
			
g.setName("g1");
g1.setStudents(students);  

session.save(c);

此时,hibernate发出如下语句:

Hibernate: insert into t_grade (name) values (?)
Hibernate: insert into t_student (studentName,gradeid) values (?, ?)
Hibernate: insert into t_student (studentName,gradeid) values (?, ?)

此时再查看数据库:

t_grade:

id   |  name

1          g1

 

t_student:

id   |  studentName   |   gradeid

1            s1                        1

2            s2                        1

已经设置了gradeid的值。

 

总结:在一对多的关联中,在一的一方设置inverse=”true”让多的一方来维护关联关系更有助于优化,因为可以减少执行update语句。


 

 

 

Author:顾故

Sign:别输给曾经的自己














郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。