Hibernate中的cascade和inverse

这段时间一直使用hibernate,使用被动控制的情况偏多,在使用主动控制时,参考并转载http://www.javaeye.com/topic/314785  这两个属性都用于一多对或者多对多的关系中。而inverse特别是用于双向关系,在单向关系中我们并不需要。

Cascade代表是否执行级联操作,Inverse代表是否由己方维护关系。

Cascade:
Cascade属性的可能值有
    all: 所有情况下均进行关联操作,即save-update和delete。
    none: 所有情况下均不进行关联操作。这是默认值。
    save-update: 在执行save/update/saveOrUpdate时进行关联操作。
    delete: 在执行delete 时进行关联操作。
    all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点。比如在一个一对多的关系中,Student包含多个book,当在对象关系中删除一个book时,此 book即成为孤儿节点。

Inverse:
Inverse属性的可能值是true或者false,默认为false:false代表由己方来维护关系,true代表 由对方来维护关系。在一个关系中,只能由一方来维护关系,否则会出问题(解疑中会讲到);同时也必须由一方来维护关系,否则会出现双方互相推卸责任,谁也 不管。

一多对的例子:

有两个类,Father和Child,是一对多的关系。下面这段hbm配置是从Father.hbm.xml中摘取的。
<set name="children" lazy="true" cascade="all" inverse="true">
    <key column="fatherid"/>
    <one-to-many class="my.home.Child"/>
</set> 
我们知道cascade和inverse的值对会有四种组合的可能(在此仅先假定cascade值为none或all)。
有如下一段代码:
Java代码
   1. FatherDao fatherDao = new FatherDao(); 
   2.  
   3. Father father = new Father("David"); 
   4. Child child1 = new Child("David Junior One"); 
   5. Child child2 = new Child("David Junior Two"); 
   6.  
   7. father.add(child1); 
   8. father.add(child2); 
   9.  
  10. fatherDao.save(father); 

FatherDao fatherDao = new FatherDao();

Father father = new Father("David");
Child child1 = new Child("David Junior One");
Child child2 = new Child("David Junior Two");

father.add(child1);
father.add(child2);

fatherDao.save(father);

1. 如果cascade="all"且inverse="false"时:
此时可以看到log里面:
Java代码
   1. // 执行对father的插入 
   2. Hibernate: insert into father (name) values (?) 
   3.  
   4. // cascade = 'all',所以进行级联操作 
   5. Hibernate: insert into child (name, fatherid) values (?, ?) 
   6. Hibernate: insert into child (name, fatherid) values (?, ?) 
   7.  
   8. // inverse = 'false',由father来维护关系(可以看到这些操作是多余的) 
   9. Hibernate: update child set fatherid =? where ID=? 
  10. Hibernate: update child set fatherid =? where ID=? 

// 执行对father的插入
Hibernate: insert into father (name) values (?)

// cascade = 'all',所以进行级联操作
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: insert into child (name, fatherid) values (?, ?)

// inverse = 'false',由father来维护关系(可以看到这些操作是多余的)
Hibernate: update child set fatherid =? where ID=?
Hibernate: update child set fatherid =? where ID=?

2. 如果cascade = "none" 且 inverse = "false":
Java代码
   1. // 执行对father的插入 
   2. Hibernate: insert into father (name) values (?) 
   3.  
   4. // inverse='false',所以更新关系 
   5. Hibernate: update child set fatherid =? where ID=? 
   6.  
   7. // 但由于cascade='none',child并未插入数据库,导致如下exception 
   8. org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance 

// 执行对father的插入
Hibernate: insert into father (name) values (?)

// inverse='false',所以更新关系
Hibernate: update child set fatherid =? where ID=?

// 但由于cascade='none',child并未插入数据库,导致如下exception
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance

3. 如果cascade = "all" 且 inverse = "true"
Java代码
   1. // 执行对father的插入 
   2. Hibernate: insert into father (name) values (?) 
   3.  
   4. // cascade='all',执行对child的插入 
   5. Hibernate: insert into child (name, fatherid) values (?, ?) 
   6. Hibernate: insert into child (name, fatherid) values (?, ?) 
   7.  
   8. //但由于inverse='true',所以未有对关系的维护。但由于一对多的关系中,关系本身在“多”方的表中。
   所以,无需更新 
   9. 关系。 

// 执行对father的插入
Hibernate: insert into father (name) values (?)

// cascade='all',执行对child的插入
Hibernate: insert into child (name, fatherid) values (?, ?)
Hibernate: insert into child (name, fatherid) values (?, ?)

// 但由于inverse='true',所以未有对关系的维护。但由于一对多的关系中,关系本身在“多”方的表中。
所以,无需更新关系。

4. 如果cascade = "none" 且 inverse = "true"

Java代码
   1. // 只执行对father的插入 
   2. Hibernate: insert into father (name) values (?) 

// 只执行对father的插入
Hibernate: insert into father (name) values (?)
可以看到,对于一对多关系,关系应由“多”方来维护(指定“一”方的inverse为true),并且应在“一”方指定相应的级联操作。

多对多:
在多对多关系中,inverse可以为任何一方,没有什么区别。

解疑:
为什么在多对多中不能由双方都来维护关系了:因为这样会导致重复更新中间表的可能,报出重复值的错误。
那么如何在多对多的双向关联中使双方都能维护关系:最好让控制关系的那方来更新关系,如果想让另一方也来维护关系,那么只有在操作这一方的数据时 “显式”更新中间表了吧。

注意:
同时注意在双向关联中,对象之间的关联跟上面提及的关系表维护没有关系。一个是对象/java层面的,一个是hibernate数据库层面的。如果你想在更新一方时,也更新另一方的对象集合,请看下面这段代码:
这是Person类中的一段代码,Person和Event是多对多的双向关联关系,他们在对方类中的集合分别为participants和 events。关系表由Person维护,所以对象关系的维护也在Person类中,而不是Event类中。

Java代码
   1. public void addToEvent(Event event) { 
   2.         this.getEvents().add(event); 
   3.         event.getParticipants().add(this); 
   4. } 
   5.  
   6. public void removeFromEvent(Event event) { 
   7.         this.getEvents().remove(event); 
   8.         event.getParticipants().remove(this); 
   9. } 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值