Inverse的作用
我们还是拿上一章的班级与学生的示例来说明问题,
请看下面的代码:
Student student1 = new Student("张三");
Student student2 = new Student("李四");
MyClass myClass = new MyClass("java0801");
Set<Student> students = myClass.getStudents();
students.add(student1);
students.add(student2);
myClassDao.create(myClass);
现在是让班级知道学生,可以观察一下控制台输出的SQL语句:
Hibernate: insert into myclass (name, id) values (?, ?)
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
Hibernate: update students set student_id=? where id=?
Hibernate: update students set student_id=? where id=?
可以看到执行了五条SQL语句,
前三台,我们可以理解,做了插入的动作,那么后面的二条Update语句是怎么来的呢?
我们先将级联的开关取消,也就是将集合的配置如下:
<set name="students">
<key column="student_id" />
<one-to-many class="chapter9.model.Student" />
</set>
测试代码:
MyClassDao myClassDao = new MyClassDao();
StudentDao studentDao = new StudentDao();
Student student1 = new Student("张三");
Student student2 = new Student("李四");
MyClass myClass = new MyClass("java0801");
Set<Student> students = myClass.getStudents();
students.add(student1);
students.add(student2);
myClassDao.create(myClass);
studentDao.create(student1);
studentDao.create(student2);
那么这时我们可以看到控制台上面的信息,发现程序出现了异常:
Hibernate: insert into myclass (name, id) values (?, ?)
Hibernate: update students set student_id=? where id=?
Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: chapter9.model.Student
我们先分析一下代码,当程序执行到myClassDao.create(myClass);这一行代码时,会执行一条INSERT SQL语句向数据库插入班级信息,我们说过,在事务开始与事务结束之间,这时的对象是持久状态,对象的状态与数据库是同步的.那么这个时候myClass发现自己的学生集合中有两个学生,那么这个时候很自然的就需要维护班级与学生之间的关系,就去数据库中将学生表中的外键更新为自己的主键.但是这个时候Hibernate又发现学生表中又没有这个学生的信息,所以就报错了(object references an unsaved transient instance,翻译后就是” 对象引用一个未保存的瞬态实例”)
如果我们要保存的话,就必须得先保存学生再保存班级.将代码改为:
studentDao.create(student1);
studentDao.create(student2);
myClassDao.create(myClass);
这时就不会报错了,
当创建学生时,因为班级还没有创建,所以学生表的外键暂时是空的,
当创建班级时,因为可以找到学生了,所以就需要更新学生表的外键为自己的主键.
我们现在可以看到执行了五条SQL语句,但是我们现在可以理解为什么要多执行两条Update语句了.
接下来我们反过来,先保存班级,再保存学生,执行下面的代码:
Student student1 = new Student("张三");
Student student2 = new Student("李四");
MyClass myClass = new MyClass("java0801");
student1.setMyClass(myClass);
student2.setMyClass(myClass);
myClassDao.create(myClass);
studentDao.create(student1);
studentDao.create(student2);
可以看到控制台只执行了三条SQL语句:
Hibernate: insert into myclass (name, id) values (?, ?)
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
我们来分析一下:
当执行myClassDao.create(myClass);这一句时,Hibernate发现此时班级对象的学生集合是空的,那么这时就不需要维护班级与学生之间的关系,因为现在还没有一个学生.
当执行到的添加学生的语句时,Hibernate发现学生对象中有一个班级对象,正好这个班级对象已经有了,那么这时候拿过来直接用就可以了.所以这时就没有多余的Update语句了.
这时说明了一个问题,在一对多的关系中,在做增加操作时,如果让一方维护关系,会多执行若干条Update语句,如果让多方来维护关系,则不会执行多余的Update语句,从而效率上要高一些.
可以打个比喻:如果让一个老师记住班上所有学生的姓名,估计难度大一些(老师需要记四十五个学生的姓名),但是如果让学生记住老师的姓名则容易的多(每个学生只需要记住一个老师的姓名即可).
Inverse的作用就是强制性的让一方不去维护自己与另一方的关系(比如强制性的让老师不去记学生的姓名),此属性通常设置在一方,即有集合的一方,比如set标签上,
<set name="students" inverse="true">
<key column="student_id" />
<one-to-many class="chapter9.model.Student" />
</set>
我们再来执行下面的代码:
MyClassDao myClassDao = new MyClassDao();
StudentDao studentDao = new StudentDao();
Student student1 = new Student("张三");
Student student2 = new Student("李四");
MyClass myClass = new MyClass("java0801");
Set<Student> students = myClass.getStudents();
students.add(student1);
students.add(student2);
studentDao.create(student1);
studentDao.create(student2);
myClassDao.create(myClass);
可以看到控制台只执行了三条Insert语句,并没有执行其它的Update语句,
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
Hibernate: insert into students (name, student_id, id) values (?, ?, ?)
Hibernate: insert into myclass (name, id) values (?, ?)
但是我们再来看看数据库
可以看到外键成了Null
这时我们就能说明Inverse的作用了,那么这时,如果我们要作增加操作的话,必须从学生那一端下手了,先创建班级,再创建学生,从而强制性的避免执行多余的Update语句了.
但是不能两端都设置这个属性为true,如果都为true,意思就是都不去维护彼此之间的关系,那么他们之间就没有关系了,从而违背了程序的本意.
接下来,我们看下面的代码:
<list name="students" inverse="true">
<key column="class_id" />
<list-index column="listindex" />
<one-to-many class="chapter2.model.Student" />
</list>
如果我们需求是需要保存学生的存储顺序,那么这时我们问题就来了,如果我们在List标签上设置了inverse="true",那么就有点说不通了,因为自相矛盾了,list集合要记住学生的顺序,那么这时他必须记住学生才行,如果我们强制性的让他不去记,那么怎么维护学生的顺序呢?
所以在Hibernate中有一个规定,在有序集合的标签中(list, array)是不能使用inverse="true"
inverse这个属性并不是所有的标签都能够设置,比如在多方
<many-to-one name="myClass" column="student_id" />
就没有这个属性设置
分享到:
相关推荐
Inverse Synthetic Aperture Radar Imaging----Victor C. Chen 第一章 ISAR成像介绍 第二章 ISAR成像基本原理 第三章 ISAR成像 第四章 ISAR运动补偿 ...第十章 双基地ISAR 第十一章 极化ISAR 第十二章 ISAR成像的应用
hibernate中inverse作用。我是一个Hibernate的初学者,前两天刚刚研究了一下inverse属性,有所心得。故把自己的小例子贴出来,与大家共享。
NHibernate Inverse & Cascade
IND Inverse Indicator.
彻底明白Hibernate中的Inverse
参数估计和反问题:《Parameter estimation and inverse problems》
Hibernate中cascade与inverse属性详解
hibernate inverse和cascade的详细讲解,相当详细全面的对inverse和cascade区别和用法的讲解
Inverse heat conduction ill-posed problems
该代码使用C语言编写,可以实现反插值,代码在实现过程中加了正则化,比常规反插值的效果要好,可以作为很好的学习和参考资料
inverse常用于一对多双向关联关系中。
Inverse Problem Theory and Methods for Model Parameter Estimation - A. Tarantola(牛叉)
The feasibility of an inverse geometry CT system
matlab开发-Pseudoinverse。矩阵因式分解用于伪逆计算
This textbook evolved from a course in geophysical inverse methods taught during the past two decades at New Mexico Tech, first by Rick Aster and, subsequently, jointly between Rick Aster and Brian ...
Inverse Scattering Theory 经典教材
COMPUTATIONAL METHODS FOR INVERSE PROBLEMS,反问题的计算方法,国外艾斯维尔出版的关于反问题求解的重要书籍,JPG版本
Parameter Estimation and Inverse Problems, Second Edition对应的第7章代码
使用Matlab实现对机器人inverse kinematics计算