对每一个对象都要执行保存,删除或重关联操作让人感觉有点麻烦,尤其是在处理许多彼此关联的对象的时候。 一个常见的例子是父子关系。考虑下面的例子:
如果一个父子关系中的子对象是值类型(value typed)(例如,地址或字符串的集合)的,他们的生命周期会依赖于父对象,可以享受方便的级联操作(Cascading),不需要额外的动作。 父对象被保存时,这些值类型(value typed)子对象也将被保存;父对象被删除时,子对象也将被删除。 这对将一个子对象从集合中移除是同样有效:Hibernate会检测到,并且因为值类型(value typed)的对象不可能被其他对象引用,所以Hibernate会在数据库中删除这个子对象。
现在考虑同样的场景,不过父子对象都是实体(entities)类型,而非值类型(value typed)(例如,类别与个体,或母猫和小猫)。 实体有自己的生命期,允许共享对其的引用(因此从集合中移除一个实体,不意味着它可以被删除), 并且实体到其他关联实体之间默认没有级联操作的设置。 Hibernate默认不实现所谓的可到达即持久化(persistence by reachability)的策略。
每个Hibernate session的基本操作 - 包括 persist(), merge(),
saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()
- 都有对应的级联风格(cascade style)。
这些级联风格(cascade style)风格分别命名为 create,
merge, save-update, delete, lock, refresh, evict, replicate
。
如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。例如:
<one-to-one name="person" cascade="persist"/>
级联风格(cascade style)是可组合的:
<one-to-one name="person" cascade="persist,delete,lock"/>
你可以使用cascade="all"
来指定全部操作都顺着关联关系级联(cascaded)。
默认值是cascade="none"
,即任何操作都不会被级联(cascaded)。
注意有一个特殊的级联风格(cascade style) delete-orphan
,只应用于one-to-many关联,表明delete()
操作
应该被应用于所有从关联中删除的对象。
建议:
通常在<many-to-one>
或<many-to-many>
关系中应用级联(cascade)没什么意义。
级联(cascade)通常在 <one-to-one>
和<one-to-many>
关系中比较有用。
如果子对象的寿命限定在父亲对象的寿命之内,可通过指定cascade="all,delete-orphan"
将其变为自动生命周期管理的对象(lifecycle object)。
其他情况,你可根本不需要级联(cascade)。但是如果你认为你会经常在某个事务中同时用到父对象与子对象,并且你希望少打点儿字,可以考虑使用cascade="persist,merge,save-update"
。
可以使用cascade="all"
将一个关联关系(无论是对值对象的关联,或者对一个集合的关联)标记为父/子关系的关联。
这样对父对象进行save/update/delete操作就会导致子对象也进行save/update/delete操作。
此外,一个持久的父对象对子对象的浅引用(mere reference)会导致子对象被同步save/update。
不过,这个隐喻(metaphor)的说法并不完整。除非关联是<one-to-many>
关联并且被标记为cascade="delete-orphan"
,
否则父对象失去对某个子对象的引用不会导致该子对象被自动删除。
父子关系的级联(cascading)操作准确语义如下:
如果父对象被persist()
,那么所有子对象也会被persist()
如果父对象被merge()
,那么所有子对象也会被merge()
如果父对象被save()
,update()
或
saveOrUpdate()
,那么所有子对象则会被saveOrUpdate()
如果某个持久的父对象引用了瞬时(transient)或者脱管(detached)的子对象,那么子对象将会被saveOrUpdate()
如果父对象被删除,那么所有子对象也会被delete()
除非被标记为cascade="delete-orphan"
(删除“孤儿”模式,此时不被任何一个父对象引用的子对象会被删除),
否则子对象失掉父对象对其的引用时,什么事也不会发生。
如果有特殊需要,应用程序可通过显式调用delete()删除子对象。
最后,注意操作的级联可能是在调用期(call time)或者写入期(flush time)作用到对象图上的。所有的操作,如果允许,都在操作被执行的时候级联到可触及的关联实体上。然而,save-upate
和delete-orphan
是在Session
flush的时候才作用到所有可触及的被关联对象上的。