Hibernate(或其它ORM)里的inverse用法详解,内容摘自Java web轻量级开发面试教程

本文来是从 java web轻量级开发面试教程从摘录的。

Inverse的英文含义是反转,在Hibernate中用来决定是由哪方来维护两个业务实体类之间的关联关系,具体而言,就是由哪方去设置这个被外键约束的字段值。

它的默认值是false,也就是说,本端(比如inverse=false写在学生端,那么本端是学生,另外一方是课程)不“反转控制权”,这句别扭的话的另外一种说法是,本端维护关联关系。如果两边都不写,那么两端都维护。这样会造成问题,即新时因为两端都控制关系,因此可能会导致重复更新。

注意,inverse仅仅是指定由谁来设置外键值,而不是用来设置级联操作,级联操作的方式由cascade来负责,很多人会混淆它们的含义和用法。

这个例子所用到的数据表是Person表和Card表,其中Person表里包含ID、Name和Phone字段,而Card表里包含了CardID、PersonID、Bank和balance四个字段。

在hibernate.cfg.xml文件里,通过mapping resource来指定对应的映射文件,其中关键的代码如下:

1	<!-- 添加实体类的映射文件-->
2	<mapping resource="Model/Card.hbm.xml" />
3	<mapping resource="Model/Person.hbm.xml" />

在Person.hbm.xml里,用如下代码来指定人(一方)和卡(多方)的关系,其中在人这一端,inverse是true。

1	<set name="cards" cascade="save-update" inverse="true">
2	<key column="PersonID"/>
3	<one-to-many class="Card"/>
4	</set>

在HibernateMain.java里,通过如下关键代码插入了一个人的信息。

1	//创建一张卡
2	Card card1 = new Card();
3	        card1.setCardID("Card123");
4	        card1.setPersonID("Person123");
5	        card1.setBank("Citi");
6	        card1.setBalance(100f);
7	//初始化一个人
8	        Person person = new Person();
9	        person.setID("Person123");
10	        person.setName("Peter");
11	        person.setPhone("123456");
12	//在cards这个set里加入card1
13	        Set<Card> cards = new HashSet<Card>();
14	        cards.add(card1);
15	        person.setCards(cards);
16	//保存人的信息
17	        session.save(person);
18	        session.flush();

运行后,在输出信息里能看到如下两条相关的插入语句:一条是插入Person信息,另一条是插入card信息。

1     Hibernate: insert into Person (Name, Phone, ID) values (?, ?, ?)

2     Hibernate: insert into Card (PersonID, Bank, Balance, Person, CardID) values (?, ?, ?, ?, ?)

当把person.hbm.xml里的inverse设置成false时,能看到相关的语句里会多出一句update语句。

1     Hibernate: insert into Person (Name, Phone, ID) values (?, ?, ?)

2     Hibernate: insert into Card (PersonID, Bank, Balance, Person, CardID) values (?, ?, ?, ?, ?)

3     Hibernate: update Card set PersonID=? where CardID=?

原因是,当设置inverse为true时,Person这一端反转外键控制权,也就是由Card这端来管理外键,而在代码里我们仅仅是插入了Person,没有插入Card,所以就没有更新两个外键(PersonID和CardID)的操作。相反,当inverse为false时,管理外键控制权是在Person端,那么当插入Person时,Hibernate就需要额外的一句update语句来管理外键了。

在一对多的例子里,inverse不论取什么值,对结果都没有影响,所以很容易让人忽视它的作用。

在一对多的例子里,一般是让多方来管理外键控制权,比如一个人有100张开,那么如果由Person方来管理的话,无形中可能会多出100个update操作,效率上就不大好了。

如果在一对多案例中,inverse只是影响效率的话,那么在多对多的例子中,inverse的设置就可能影响到数据。

我们再来看个多对多的学生选课案例,其中一个学生可以选多门课,而一门课里可以有多个学生。在Student.hbm.xml里,描述多对多关系的语句里可加上inverse=“true”的语句。

1	<set name="courses" table="students_courses" inverse= "true" cascade="save-update">
2	<key column="student_id"></key>
3	<many-to-many class="Model.Course" column="course_id"></many-to-many>
4	</set>

在Course.hbm.xml里,不加任何关于inverse的语句,也就是说,在Student端反转外键控制权,把控制权交到Course端。

在HibernateMain这个类里,通过如下代码让s1学生选修计算机课程。

1	        //设置一个学生,学号是1
2	Student s1 = new Student();
3	        s1.setStudentID("1");
4	        s1.setStudentName("Peter");
5	//设置多个课程
6	        Course c1 = new Course();
7	        c1.setCourseID("c1");
8	        c1.setCourseName("Math");
9	        Course c2 = new Course();
10	        c2.setCourseID("c2");
11	        c2.setCourseName("Java");
12	        Course c3 = new Course();
13	        c3.setCourseID("c3");
14	        c3.setCourseName("C#");
15	//设置计算机课程这个Set
16	        Set<Course> computerCourses = new HashSet<Course>();
17	        computerCourses.add(c2);
18	        computerCourses.add(c3);
19	//让s1这个学生选修计算机课程(也就是c2和c3课程)
20	        s1.setCourses(computerCourses);
21	//保存s1
22	        session.save(s1);
23	        session.flush();

执行结果是,虽然能在Student和Course表里看到相关的学生和课程的记录,但在关键的描述学生选课关联表(students_courses)里,看不到任何关联记录。原因是已经通过设置inverse把外键管理权交给Course方了,这里仅仅是保存学生,并没有保存课程,所以没有插入外键的动作。如果要在students_courses表里插入外键关联,就需要在person.hbm.xml里设置inverse的值为false。

所以,在多对多关联里,设置错了inverse值会导致结果出错,请大家根据具体项目的情况适当设值。

  

  

时间: 2024-08-10 15:08:13

Hibernate(或其它ORM)里的inverse用法详解,内容摘自Java web轻量级开发面试教程的相关文章

XStream 用法详解 XML 转换为 java 实体类

XStream 用法详解 java 类与 XML 互换 现在 WEB数据交换的时代,传送XML目前是一个比较流行的方式,具有统一的规则约束,为实现后台接口提供了一个很方便的实现. 我编写了一个 接收XML并转换成所需要的Object类的 小例子,希望能够对做互联网数据传输.接口调用的朋友有所帮助. 首先要导入jar包xstream-1.4.3-sources.jar 和 xmlpull-1.1.3.1.jar 两个包: 其次是预备一个 XML 事例 <config> <span styl

【SSH三大框架】Hibernate基础第十篇:inverse属性详解

inverse经常用在双向的1-N关联之中,也可以用在N-N的关联,这里举例子用双向的1-N关联 还是用部门和员工两个,关于两个的javabean不再写. 首先,我们看下员工的映射文件: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourcef

1.12-linux三剑客之awk用法详解

1.12 linux三剑客之awk用法详解 内容: 1. awk执行过程 2. awk命令格式 3. awk用法 4. awk数组 第1章 awk执行过程 一直读取到文件的最后一行 第2章 awk '找谁{干啥}' '模式{动作}' 模式 pattern   动作  action 第3章 awk中什么可以作为模式 正则表达式 比较表达式    NR>10 范围模式 特殊模式BEGIN{}和END{} awk支持正则中的特殊符号 3.1 正则表达式 测试文件/server/files/reg.tx

BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)

转自:https://blog.csdn.net/ochangwen/article/details/51531866 一.简介 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal.BigDecimal所创建的是对象,我们不

CSS中伪类及伪元素用法详解

原文:CSS中伪类及伪元素用法详解 伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的读者可以自己尝试: :active  大致效果为用鼠标点击时,元素增加特效,鼠标松开时,特效消失.多用在按钮的点击上. 写法: 这里id为box的是一div块,在css中首先设置了他的基本样式,下面为加入:active伪类后需要修改的样式. 未点击时: 点击之后: :active.:hover.:

java中静态代码块的用法 static用法详解

(一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的. 静态方法在类加载的时候 就已经加载 可以用类名直接调用比如main方法就必须是静态的 这是程序入口两者的区别就是:静态代码块是自动执行的;静态方法是被调用的时候才执行的.静态方法(1)在Java里,可以定义一个不需要创建对象的方法,这种方法就是

linux dd命令参数及用法详解---用指定大小的块拷贝一个文件(也可整盘备份)

linux dd命令参数及用法详解---用指定大小的块拷贝一个文件 日期:2010-06-14 点击:3830 来源: 未知 分享至: linux dd命令使用详解 dd 的主要选项: 指定数字的地方若以下列字符结尾乘以相应的数字: b=512, c=1, k=1024, w=2, xm=number m if=file 输入文件名,缺省为标准输入. of=file 输出文件名,缺省为标准输出. ibs=bytes 一次读入 bytes 个字节(即一个块大小为 bytes 个字节). obs=b

oracle中的exists 和not exists 用法详解

oracle中的exists 和not exists 用法详解 有两个简单例子,以说明 “exists”和“in”的效率问题 1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ; T1数据量小而T2数据量非常大时,T1<<T2 时,1) 的查询效率高. 2) select * from T1 where T1.a in (select T2.a from T2) ; T1数据量非常大而T2数据量小时,T1>

一步一步学ios UITextView(多行文本框)控件的用法详解(五5.8)

本文转载至 http://wuchaorang.2008.blog.163.com/blog/static/48891852201232014813990/ 1.创建并初始化 创建UITextView的文件,并在.h文件中写入如下代码: [csharp] view plaincopy #import <UIKit/UIKit.h> @interface TextViewController : UIViewController <UITextViewDelegate> { UITe