🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 10.11\. 传播性持久化(transitive persistence) 对每一个对象都要执行保存,删除或重关联操作让人感觉有点麻烦,尤其是在处理许多彼此关联的对象的时候。 一个常见的例子是父子关系。考虑下面的例子: 如果一个父子关系中的子对象是值类型(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()`操作 应该被应用于所有从关联中删除的对象。 建议: * 通常在`&lt;many-to-one&gt;`或`&lt;many-to-many&gt;`关系中应用级联(cascade)没什么意义。 级联(cascade)通常在 `&lt;one-to-one&gt;`和`&lt;one-to-many&gt;`关系中比较有用。 * 如果子对象的寿命限定在父亲对象的寿命之内,可通过指定`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)的说法并不完整。除非关联是`&lt;one-to-many&gt;`关联并且被标记为`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的时候才作用到所有可触及的被关联对象上的。