Hibernate中cascade与inverse属性详解

开发 后端
本篇文章主要讲解关于Hibernate中cascade与inverse的理解。希望对大家有所帮助。

关于Hibernate中 cascade 与 inverse 的理解。

您买的Hibernate书是哪一本呢? 孙卫琴的精通Hibernate,还是 深入浅出Hibernate还是那本。。。

我是两本都买了,总体来说还可以,但是,有的地方讲的比较书面化,比如inverse这属性。

在学习Hibernate的过程中最不好理解的就是这两个属性了。

(我当初学习Hibernate的时候,发现网上介绍这两个属性的文章倒是不少,但是,居然有好多都是转帖。。。还有的就是 照书搬~~-_-!!!)。。。

据个例子:书上说inverse=false时,由主控方维持关系。。。

由于我也是初学者。。。再加上语文水平偏低。。。不理解“维持关系是啥意思”囧~

提示:

(1)如果:您不了解Hibernate的one-to-many或many-to-one的概念。

(2)如果:你不了解Hibernate的“自由态”“持久态”“游离态”的概念。

(3)如果:您不了解Hibernate中的“脏数据”的概念。

(4)如果:您对Hibernate中Session缓存,没有初步了解的话。

(在Hibernate中调用save进行存储数据的时候,并不是马上就对数据库进行insert操作,而是会将其“数据对象(vo)”纳入Hibernate的Session缓存。)

在上面的4条提示中,如果您对其中的某一条,不是很清楚的话。希望请先了解有关知识。

否则,可能您将 “无法或很难”理解 cascade 或 inverse 这2个属性。

首相,cascade 与 inverse 这两个属性,其实是完全不同的两个东西,想要了解他们各自的“用途与区别”,详见如下介绍:

这里有两个表:

(1)class (班级表)

相应字段:

cid varchar(32) 主键 not-null (班级id)

cname varchar(16) not-null (班级名称)

(2)student (学生表)

相应字段:

sid varchar(32) 主键 not-null (学生id)

sname varchar(16) not-null (学生姓名)

class_id varchar(32) not-null (学生所属班级)

一个班级(class)对应多个学生(student),所以班级表(class)就是“one-to-many”端

反之student就是many-to-one

 

  1. //--------Class类的代码--------  
  2.  
  3. public class Class implements.....  
  4.  
  5. {  
  6.  
  7. private cId = "";  
  8.  
  9. private cName = "";  
  10.  
  11. private students = java.util.HashMap();  
  12.  
  13. // 省略对应的 geter setter  
  14.  
  15. }  
  16.  
  17. //--------Class.hbm.xml--------  
  18.  
  19.  
  20.  
  21. <class name="lcx.vo.Class" table="class" 
  22.  
  23.    catalog="demo">  
  24.  
  25.    "cid" type="java.lang.String">  
  26.  
  27.     "cid" length="32" />  
  28.  
  29.     class="uuid.hex" />  
  30.  
  31.      
  32.  
  33.    "name" type="java.lang.String">  
  34.  
  35.     "cname" length="16" not-null="true" />  
  36.  
  37.      
  38.  
  39.     
  40.  
  41.    "students" table="student" cascade="save-update">  
  42.  
  43.     "class" />  
  44.  
  45.     class="lcx.vo.Student" />  
  46.  
  47.       
  48.  
  49. class>  
  50.  
  51.  
  52.  
  53. //--------Student类的代码;*******  
  54.  
  55. public class Student implements.....  
  56.  
  57. {  
  58.  
  59. private sId = "";  
  60.  
  61. private sName = "";  
  62.  
  63. private Class class = null;  
  64.  
  65. // 省略对应的 geter setter  
  66.  
  67. }  
  68.  
  69. // Student.hbm.xml  
  70.  
  71.  
  72.  
  73. <class name="lcx.vo.Student" table="student" catalog="demo">  
  74.  
  75.    "cid" type="java.lang.String">  
  76.  
  77.     "sid" length="32" />  
  78.  
  79.     class="uuid.hex" />  
  80.  
  81.      
  82.  
  83.    "class"   
  84.  
  85.     class="lcx.vo.Class" 
  86.  
  87.     column="class_id"   
  88.  
  89.     not-null="true"   
  90.  
  91.    />     
  92.  
  93. class>  
  94.  
  95.  
  96.  

 

 

(一) cascade 的介绍:

当Hibernate持久化一个“临时对象(也叫自由态对象)”时,在默认的情况下(即:没有设置cascade属性或cascade=none时),Hibernate不会自动“持久化他所关联”的其他临时对象。

上面这些话是什么意思呢? 什么叫不会自动 “持久化”关联的临时对象呢?

看如下代码:

 

  1. // 创建一个 临时对象(也叫自由态对象)   
  2.  
  3. // 也就是说这个 class 没有被Hibernate纳入Session缓存管理。  
  4.  
  5. Class class = new Class();  
  6.  
  7. //class.id 为自动生成  
  8.  
  9. class.setName("一年级1班");  
  10.  
  11. Student stu = new Student();  
  12.  
  13. //student.id 为自动生成  
  14.  
  15. stu.setName("小白兔");  
  16.  
  17. stu.setClass(class);  
  18.  
  19. // 关键就是这里。。。  
  20.  
  21. class.getStudents().add(stu);  
  22.  
  23. session.save(class);  
  24.  
  25. // 提交  
  26.  
  27. // 注意: Class.hbm.xml文件中,cascade="save-update"并且也没有设置inverse属性,也就是说inverse=false;  
  28.  
  29. // 此时如果你开启了Hibernate的显示HQL语句功能,那么控制台将会显示如下3条HQL:  
  30.  
  31. //----------------------------------------********  
  32.  
  33. insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)  
  34.  
  35. insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)  
  36.  
  37. update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888  
  38.  
  39. //----------------------------------------********  
  40.  

 

那么为什么会出现,这3条HQL语句呢,我们来一一分析一下:

第1条HQL语句:

其实第一条HQL比较好理解,

当我们调用 session.save(class) 后,在Hibernate进行提交的时候,

会发现“有”一条“新”的数据要插入(insert),所以就往class表中,插入了这条新的class记录。

第2条HQL语句:

注意问题就在这里:

这里为什么又出现了一条insert语句呢?而且还是向student表中插入数据。

我们在上面的代码中,并没有编写类似“session.save(student)”这样的语句啊。

这是为什么呢?

其实原因,是这么回事:因为我们在class端,设置了"级联更新"(即:cascade="save-update"),

也就是说,当Hibernate在向class表中插入“新”对象记录时,会检查“Class对象”所关联的属性(就是对应的属性),是否发生过变化,如果发生了变化,就按照“级联属性(cascade)”所设定的内容

进行操作。

上面讲的这句话到底是什么意思呢?

用你们“人”话说,就是:

因为调用了 class.getStudents().add(stu);

所以,在Hibernate在进行插入 class对象的时候,发现class对象,所关联的集合中,有一条

“自由态”的对象,而又因为class端设置了“级联属性cascade”,所以,在插入这条 “新class对象”时,也一同把他内部的那些,还属于“自由态”的其他对象,也一同插入到,他们所对应的表中去了。

还是不明白的话。。。可以看看。孙卫琴的《精通Hibernate》,在书上的第149页有。

但是关于inverse的介绍。。。写的就有些书面化了,如果语文不好的话。。。就难懂咯~

第3条HQL语句:

第三条HQL语句是一条update语句,是不是觉得,很莫名其妙。。。。

Hibernate大脑进水了吧,怎么吃饱了撑得,重复更新记录啊啊啊啊啊

假如:我们把 class端的配置文档中的 invser属性设置为true(即:inverse=true)

在执行上面的程序,发现,就变成2条insert语句啦。。。。。(update没啦。。。)

看来第三条的update语句和inverse有着密切的关系(他两有一腿~)。

所以我们下边,就来介绍一下inverse属性:

当调用 Class.getStudents().add(stu)方法,进行添加操作时,

(即:向 "这个Class对象"所属的“集合 (也就是调用getStudents方法所返回的那个Set集合)”中添加一个Student(即 add(stu)),也就是说,这个“新”添加的Student对象(stu),

他的Student.class_id字段“必须”,要等于“被添加方Class”的主键(即:Class.cid)。

从“数据库”层面来讲,也就是说,这个“新”添加的“Student”的class_id字段,必须要与“Class”的cid字段,存在"主外键关联"。)

正因为如此:所以Hibernate“怕” 在进行 "Class.getStudents().add(stu)" 这样的操作时,

出现意外情况(如: stu.getClass=null,即:stu没有所属班级),

即“添加方”(Student)与“被添加方”(Class),存在“外键”不一致的情况发生。

所以就出现了 那条多余的update语句。即:one-to-many(Class端)主动去维护Child.Class_id

所以就是说,Hibernate怕出错,就给你多执行一次无用的更新语句,以保证 add 到 Class“集合”中的所有Student

都是要与Class有外键关联的。

用普通话说就是:

一年1班.getStudents().add(小白兔);

一年1班.getStudents().add(大白兔);

也就是说现在不管是 小白兔 还是 大白兔

如果他们,目前还没有自己的班级的话,

一年1班的班主任就会主动邀请他们成为一年1班的同学啦~。

也就是说 一年1班的班主任 主动邀请 同学,而不是 同学自己来~~~ 所以效率也降低了。。。。

所以我们一般把 一对多端 invser设置为true,即:不让主控端去维护主键关联,

(即:让同学自己去找班级)

说白了,就是,one-to-many端不用去管理 “新添加对象” 的主外键约束问题。

把one-to-many端(即:class端)的invser设置为true

(即:每次向class.getStudents这个集合中添加 student时,不去主动update对应的外键),

而是在student端去手动设置

例如:

 

  1. student.setClass(class);  
  2.  
  3. session.save(student);  
  4.  
  5. 这样手动设置 student与class关联啦。。。。  
  6.  
  7. 所以上面的程序“最好”还是写成这样:  
  8.  
  9. Class class = new Class();  
  10.  
  11. class.setName("一年级1班");  
  12.  
  13. session.save(class);  
  14.  
  15. Student stu = new Student();  
  16.  
  17. stu.setName("小白兔");  
  18.  
  19. stu.setClass(class);  
  20.  
  21. session.save(class);  
  22.  
  23. /*  
  24.  

 

此时向class集合add内容,不会进行数据库操作(update)。

“更新”的只是session缓存中,数据镜像。

这样做的好处是:不仅减少了update语句,

而且,同时也更新了session缓存。

------------------------

而在原来:

one-to-many端inverse=false时,虽然也更新seesion缓存中的class集合,

但是有却又多余update

 

  1. */  
  2.  
  3. class.getStudents().add(stu);  
  4.  
  5. // 提交  

 

总结:

当inverse=false 并且向one-to-many端的关联集合,添加“新对象(即: 自由态对象)” 时,

Hibernate就会自动,去update那“个刚刚到来的” “自由态对象”的外键。

(如果你向,one-to-many端添的集合中,add一个“已经持久化了的对象”,那就不会出现update了(因为已经持久化过了),除非,你去 更改“那个持久化对象”所对应的外键。。。那样的话。。。呵呵呵~~~

你可以试一试,应该不会报错,你可以当做练习去做一下,加深cascade和inverse这两个属性的理解)

// 如果看懂了上面的内容。来看一下,下面的东西。

假如,将one-to-many端(即:Class端)的 hbm.xml 文档中的cascade移除掉 或把cascade="none"。

那么上面的代码会出现什么情况呢。

结果会出现2条HQL,和一堆Exception

 

  1. insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年级1班)  
  2.  
  3. update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888  
  4.  
  5. Hibernate Exceptinon......................................   
  6.  

 

相比较cascade被设置"save-update"的时候,缺少了1条 insert语句,而且也多了一些Exception。

那么,到底是少了哪1条insert语句呢?

就是这条:

 

  1. insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)  
  2.  

之所以会出现,这样的现象,想必您已经早就看出来了。

因为,我没有设置Class端的Cascade,所以在save(class)的时候,并没有自动将其所关联的“自由态对象”进行持久化操作。

然而,又因为 Class端的inverse=false,所以,Class会自动去维持,那个 “新来的student” 的外键。

所以会出现,没有insert就要update啦。。。。

然后在就是Exception了

【编辑推荐】

  1. Hibernate批量更新与删除实例浅析
  2. 简述Hibernate Synchronizer学习笔记
  3. Hibernate column属性简介
  4. 概括Hibernate查询语言
  5. Hibernate cartridge学习总结
责任编辑:金贺 来源: ITEYE博客
相关推荐

2012-02-03 10:21:47

HibernateJava

2009-09-22 09:40:03

cascade和invHibernate

2009-06-12 14:52:21

cascadeinverseHibernate

2009-09-23 08:56:18

Hibernate cHibernate i

2009-06-18 10:29:24

Hibernate I

2009-06-12 15:05:03

cascadeHibernate

2009-07-09 16:01:27

2009-09-24 13:03:38

Hibernate C

2009-06-29 08:59:05

hbm的generat

2009-09-23 12:48:54

Hibernate I

2009-09-23 13:33:51

Hibernate属性

2009-09-29 17:00:08

Hibernate c

2009-09-24 17:24:20

Hibernate S

2009-09-21 17:33:50

Hibernate基础

2009-07-02 09:34:05

hibernate的l

2009-09-28 09:56:53

Hibernate属性

2009-09-25 13:39:40

Hibernate属性

2009-09-27 13:57:19

Hibernate树形

2010-09-07 16:46:59

CSSexpression

2009-09-24 15:53:00

Hibernate J
点赞
收藏

51CTO技术栈公众号