【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:别输给曾经的自己

时间: 2024-10-05 05:07:34

【Hibernate】详解Hibernate中的inverse=”true”的相关文章

hibernate 详解

 Hibernate 1 Hibernate的配置文件 1.1 cfg 该文件的后缀为*.cfg.xml hibernate配置文件,该文件中主要存放了 数据的url地址 数据库用户信息 缓存 mapping文件的配置路径 <session-factory > <property name="connection.url">jdbc:oracle:thin:@192.168.8.62:1521:orcl</property> <proper

图解、详解Hibernate多对一映射

步骤1:案例代码. 步骤2:案例图解分析. ------------------------------------------------------------------------步骤1:案例代码------------------------------------------------------------------------------------------------------------------- 我们讲解Hibernate多对一映射的时候,首先想到的就是经典的

用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)

用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是IoC的另外一种说法,只是从不同的角度描述相同的概念.看完这两句,是不是不但没懂,反而更迷惑了,别急,往下看: IoC的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 如果我们打开机械式手表的后盖,就会看到与

详解Webwork中Action 调用的方法

详解Webwork中Action 调用的方法 从三方面介绍webwork action调用相关知识: 1.Webwork 获取和包装 web 参数 2.这部分框架类关系 3.DefaultActionProxyFactory.DefaultActionProxy.DefaultActionInvocation 终于要开始 webwork 核心业务类的总结,webwork 通过对客户端传递的 web 参数重新包装,进行执行业务 Action 类,并反馈执行结果,本篇源码分析对应下图 WebWork

详解Objective-C中委托和协议

Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于“委托”则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可以实现委托. AD:[活动]Web和APP兼容性实战 Win10训练营免费报名 Objective-C中委托和协议是本文要介绍的内容,委托和协议是两个概念,协议实际上相当于C++中的纯虚类的概念,只定义并只能由其它类来实现.而委托类似于Java中的接口.(Objective-C实现委托这种机制是利用协议来实现的,这种说

详解js中typeof、instanceof与constructor

详解js中typeof.instanceof与constructor typeof返回一个表达式的数据类型的字符串,返回结果为js基本的数据类型,包括number,boolean,string,object,undefined,function.语法为typeof(data) 或 typeof data instanceof则为判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例;返回boolean类型 语法为 o instanceof A 以下为综合实例: 1<script type

详解C#中System.IO.File类和System.IO.FileInfo类的用法

System.IO.File类和System.IO.FileInfo类主要提供有关文件的各种操作,在使用时需要引用System.IO命名空间.下面通过程序实例来介绍其主要属性和方法. (1) 文件打开方法:File.Open () 该方法的声明如下:     public static FileStream Open(string path,FileMode mode)  下面的代码打开存放在c:\tempuploads目录下名称为newFile.txt文件,并在该文件中写入hello. pri

详解Struts1中的struts-config.xml配置文件【一】

搞清楚struts-config.xml中各项元素的作用,对于我们构建web项目有莫大的好处.<struts-config>是struts的根元素,它主要有8个子元素,DTD定义如下: <!ELEMENT struts-config (data-sources?,form-beans?,global-exceptions?,global-forwards?, action-mappings?,controller?,message-resources*,plug-in*)> 以上8

(转)详解Android中AsyncTask的使用

转载自:详解Android中AsyncTask的使用 在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制.关于Handler的相关知识,前面也有所介绍,不清楚的朋友们可以参照一下. 为了简化操作,Android1.5提供了工具类a

详解C#中Socket通信(一):实现连接

第一步:实现连接 客户端连接代码: private void connect2Server() { Socket clientSocket; //服务器地址 IPAddress ip = IPAddress.Parse("192.168.1.136"); //服务器节点 IPEndPoint iep = new IPEndPoint(ip, 9004); //通信实例 clientSocket = new Socket(AddressFamily.InterNetwork, Socke