`

hibernate 中inverse cascade属性

阅读更多

hibernate中一对多关联时会经常用到inversecascade属性 ,inverse 有两个值 true ,false  ;如果设置为true 则表示当前对象不负责将级联对象的状态变化同步到数据库 ;设置false则相反,其默认值为false;
cascade 有五个选项 分别是: all ,delete ,none,save-update,delete-orphan ;
       
all : 所有情况下均进行关联操作。
        none
:所有情况下均不进行关联操作。这是默认值
        save-update:
在执行save/update/saveOrUpdate时进行关联操作。
        delete
:在执行delete时进行关联操作。
        delete-orphan: 
save/update/saveOrUpdate时,相当于save-update ;当删除操作时,相当于delete
all的意思是save-update + delete
all-delete-orphan 的意思是当对象图中产生孤儿节点时,在数据库中删除该节点
all比较好理解,举个例子说一下all-delete-orphan:
Category
(种类)与Item是一对多的关系,也就是说Category类中有个Set类型的变量items.
举个例子,items中存两个Item, item1,item2,如果定义关系为all-delete-orphan
items中删除掉一个item(比如用remove()方法删除item1),那么被删除的Item类实例
将变成孤儿节点,当执行category.update(),session.flush()
hibernate同步缓存和数据库,会把数据库中item1对应的记录删掉测试Hibernate中的三个属性:lazy,inverse,cascade
【测试环境】
一对多关系的两张表:boygirl(一个男孩可以多个女朋友)
 boy表结构
 Field   Type        

------  ----------- 
 name    varchar(50)  pk
 age     varchar(50) 

 girl表结构
 Field   Type        
 ------  ----------- 
 name    varchar(50)  pk
 bf      varchar(50)  fk 
【保存时:Inversecascade
 创建三个girl对象和一个boy对象,让这是三个girl都是boy的女朋友

  ---------创建对象的代码片段-----------
  Boy boy = new Boy("tom","23", null);

 Set girls = new HashSet(); 
  Girl g[] = new Girl[]{
                        new Girl("Alice1", boy),
                        new Girl("Alice2", boy),
                        new Girl("Alice3", boy)};
  girls.add(g[0]);
  girls.add(g[1]);
  girls.add(g[2]);
  boy.setGirls(girls); 
 
Boy.hbm.xml中设置,然后对boy对象进行保存。
1.Inverse = true,不指定cascade
  
cascade的默认值为none, 当对boy进行保存操作时,girl什么都不做. 所以只保存了boy对象, 没有保存girl对象
2.Inverse = truecascade=all
   boy
girl对象,包扩外键都成功保存。
(生成3SELECT语句和4INSERT语句,一下简称SELECT 3, INSERT 4)
3.Inverse = false,不指定cascade
  
报错。因为boy为主控方,负责维护关系,所以在插入boy对象后,会尝试修改并不存在的girl对象。
 4.Inverse = falsecascade=all
   boy
girl对象,包扩外键都成功保存。
   (SELECT 4, INSERT 4, UPDATE 3)

 分析:除了4INSERT语句之外,其他的6条语句是我们为了图方便付出的代价:3SELECT语句用来判断girl对象是否在数据表中已经存在,3UPDATE语句是为了维护外键关系
高效率的做法:在Boy.hbm.xml中设置Inverse=true,在Girl.hbm.xml中设置Inverse=false, cascade=all,然后保存三个girl对象
 (SELECT 1, INSERT 4)

高效率的代价就是保存的时候比较麻烦
【删除时:Inversecascade
希望通过删除boy,也将3girl对象删除。程序中先查出boy对象,然后进行删除
  -----------------------------------------
  Boy boy = (Boy) s.get(Boy.class, "tom");
  s.delete(boy);
  -----------------------------------------
 
同样在Boy.hbm.xml中进行设置
1.Inverse = true
  
可以猜到结果是出错。原因:外键约束错误

 2.Inverse = false
   boy
删除,girl表中外键变为null,没有删除记录 ;  
(UPDATE 1, DELETE 1)

3.Inverse = false, cascade = all
         
全部删除  ;在删除有外键的从表时,先把从表外键置为null,然后删除主表记录,最后根据从表主键删除所有相关从表记录
   (UPDATE 1, DELETE 4)

 4.Inverse = true, cascade = all
 全部删除
 (DELETE 4)

Inversehibernate双向关系中的基本概念,当然对于多数实体,我们并不需要双向关联,更多的可能会选择单向关联,况且我们大多数人一般采用一对多关系,而一对多双向关联的另一端:多对一的inverse属性是不存在,其实 它默认就是inverse=false.从而防止了在一对多端胡乱设置inverse也不至于出错。但是inverse设置不当确实会带来很大的性能影响,这点是我们必须关注的。这篇文章已经详细分析了inverse设置不当带来的影响:http://www.hibernate.org/155.html
看了这篇文章,还是很有必要再写下一些总结的:
1inverse中提及的side其实是指一个类或者表的概念,双向关联其实是指双方都可以取得对方的应用。
2)维护关系这个名词还是稍显模糊或者晦涩。我们一般说A类或者A表(这里的表的是指多对多的连接表)有责任维护关系,其实这里的意思是说,我在应用在更新,创建,删除(读就不用说了,双向引用正是为了方便读而出现)A类或者A表时,此时创建的SQL语句必须有责任保证关系的正确修改。
3inverse=falsesideside其实是指inversefalse所位于的class元素)端有责任维护关系,而inversetrue端无须维护这些关系。
4)我们说inverse设立不当会导致性能低下,其实是说inverse设立不当,会产生多余重复的SQL语句甚至致使JDBC exceptionthrow。这是我们在建立实体类关系时必须需要关注的地方。一般来说,inversetrue是推荐使用,双向关联中双方都设置 inversefalse的话,必会导致双方都重复更新同一个关系。但是如果双方都设立inversetrue的话,双方都不维护关系的更新,这也是 不行的,好在一对多中的一端:many-to-one默认是inversefalse,避免了这种错误的产生。但是多对多就没有这个默认设置了,所以很多人经常在多对多的两端都使用inversetrue,结果导致连接表的数据根本没有记录,就是因为他们双分都没有责任维护关系。所以说,双向关联中最好的设置是一端为inversetrue,一端为inversefalse一般inversefalse会放在多的一端,那么有人提问了, manytomany两边都是多的,inverse到底放在哪儿?其实hibernate建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。
看下面的多对多的定义大家更会清楚多对多一对多的关系:其中我们注意<many-to-many />标签的特点就知道,它是定义了一个多对多关系,而不是<one-to-many/>

<?xml version="1.0"?>
<!DOCTYPE
hibernate-mapping PUBLIC
 "-//
Hibernate/Hibernate Mapping DTD 2.0//EN"://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping  package="org.hibernate.auction">
 <class name="TestA" table="TestA"
 dynamic-update="true" dynamic-insert="true" >
<id name="id" column="id" type="int" unsaved-value="any" >
   <generator class="assigned">
   </generator>
  </id>
<property name="name" type="java.lang.String"
   update="true" insert="true" column="name" />
<set name="testBs" table="TestA_TestB" inverse="false" cascade="all">
   <key column="testA"/>
   <many-to-many column="testB" class="TestB" />
  </set>
</class>
 <class name="TestB" table="TestB"
 dynamic-update="true" dynamic-insert="true" >
 <id name="id" column="id" type="int" unsaved-value="any" >
   <generator class="assigned">
   </generator>
  </id>
<property name="name" type="java.lang.String" update="true"
  insert="true" column="name" />

<set name="testAs" table="TestA_TestB" inverse="true" cascade="all">
   <key column="testB"/>
   <many-to-many column="testA" class="TestA" />
  </set>

 </class>
</
hibernate-mapping>
在对多对中,因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类建立关系,因为这样建立的关系是不会在数据库中存储的。基于上面的映射文件代码给出一个例子:
package org.hibernate.auction;
import java.util.*;

/**
 * @author Administrator
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class TestA {
 int id;
 String name;
 Set testBs=new HashSet();
 public TestA(){
  }
 public TestA(int id){
  setId(id);
 }
 public int getId(){
  return id;
 }
 public void setId(int id){
  this.id=id;
 }
 public String getName(){
  return name;
 }
 public void setName(String name){
  this.name=name;
 }
 public Set getTestBs(){
  return testBs;
 }
 public void setTestBs(Set s){
  testBs=s;
 }
 public void addTestB(TestB tb){
  testBs.add(tb);

 }

 public static void main(String[] args) {
 }
}

public class TestB {
int id;
String name;
Set testAs=new HashSet();
 public TestB(){
 }
 public TestB(int id){
  setId(id);
 }
 public int getId(){
  return id;
 }
 public void setId(int id){
  this.id=id;
 }
 public String getName(){
  return name;
 }
 public void setName(String name){
  this.name=name;
 }
 public Set getTestAs(){
  return testAs;
 }
 public void setTestAs(Set s){
  testAs=s;
 }
 public void addTestA(TestA ta){
  testAs.add(ta);
 }

 public static void main(String[] args) {
 }
}

测试代码:

public void doTest() throws Exception{
  TestA a1=new TestA(1);
  TestA a2=new TestA(2);
  TestA a3=new TestA(3);
  TestB b1=new TestB(1);
  TestB b2=new TestB(2);
  TestB b3=new TestB(3);
  a1.addTestB(b1);
  a1.addTestB(b2);
  a1.addTestB(b3);
  b2.addTestA(a1);
  b2.addTestA(a2); 
  Session s = factory.openSession();
  s = factory.openSession();
  Session session = factory.openSession();
  session.save(a1);
  session.flush();
  session.close();

 }
测试后连接表的数据为:
testa              testb
1                    1
1               2
1                    3
根据inverse规则,对这些代码:b2.addTestA(a1);  b2.addTestA(a2); 建立的关系,数据库并没有存储下来,因为TestB没有责任维护这些关系,所以产生的sql语句自然不会有针对Testa_testB表的操作了。假设应用中真的需要这些方法,那么我们可以修改TestB的方法,让他们注意在维护端类中执行相应的操作以使得关系能够在数据库中保存下来,更改TestB 下:/*
 * Created on 2004-7-25
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package org.
hibernate.auction;
import java.util.*;

/**
 * @author Administrator
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class TestB {

 
 int id;
 String name;
 Set testAs=new HashSet();
 public TestB(){ 
 }
 public TestB(int id){
  setId(id);
 }
 public int getId(){
  return id;
 }
 public void setId(int id){
  this.id=id;
 }
 public String getName(){
  return name;
 }
 public void setName(String name){
  this.name=name;
 }
 public Set getTestAs(){
  return testAs;
 }
 public void setTestAs(Set s){
  testAs=s;
 }
 public void addTestA(TestA ta){
  testAs.add(ta);
  ta.addTestB(this);
 }

 public static void main(String[] args) {
 }
}
那么测试执行后连接表的数据为:

testa    testb

1               2

1               3

1                1

2                 2
测试通过。
hibernate cascade备忘
当关联双方存在父子关系,就可以在 set 处设定 cascade all-delete-orphan
所谓父子关系,即指由父方控制子方的持久化圣明周期,子方对象必须和一个父方对象关联。如果删除父方对象,应该级联删除所有关联的子方对象;如果一个子方对象不再和一个父方对象关联,应该把这个子方对象删除。
all-deleteorphan
的能力:
1.
当保存或更新父方对象时,级联保存或更新所有关联的子方对象,相当于 cascade save-update
2.
当删除父方对象时,级联删除所有关联的子方对象,相当于 cascade delete
3.
删除不再和父方对象关联的所有子方对象
解除父子关系的 java 语句例如:
customer.getOrders().remove(order);
order.setCustomer(null);

Arial;" />tx.commit();
如果 cascade 属性取默认值 null,当解除父子关系时,会执行如下 sql
update ORDER set CUSTOMER_ID=null where ID=2
inverse
设定的原则:
1.
在映射一对多双向关联关系时,应该设定 many 方的 inverse true,以提高性能
2.
在建立两个对象的双向关联时,应同时修改关联两端的对象的相应属性:
1
customer.getOrders().add(order);
2
order.setCustomer(customer);

如果不执行 1)而仅执行 2),由于 set 元素的 inverse true,因此 hibernate 不会按照 CUSTOMER 对象的状态变化来同步数据库。
inverse
解决性能问题的例子:
1.
建立 Order Customer 的多对一关联关系
order.setCustomer(customer);
相应执行的 SQL 为:
update ORDERS set ORDER_NUMBER=''''Jack_Order001'''', CUSTOMER_ID=2 where ID=2;
2.
建立 Customer Order 的一对多关系
customer ORDERS set CUSTOMER_ID=2 where ID=2;

/>相应 SQL 为:
update ORDERS set CUSTOMER_ID=2 where ID=2;
显然 1 2 SQL 功能重复了,反复执行这样的 SQL 语句会引起性能下降,因此:
inverse
设定为 true 时,声明 Customer 端的关联只是 Order 端关联的镜像。当两者状态发生变化时,Hibernate 仅按照 Order 对象状态变化来同步数据库。即仅会执行以下 SQL
update ORDERS set ORDER_NUMBER=''''Jack_Order001'''', CUSTOME_ID=2 where ID=2;
Customer.hbm.xml
片段如下:
<set
name="orders"
cascade="all-delete-orphan"
inverse="true"
>
<key column="CUSTOMER_ID" />
<one-to-many class="mypack.Order" />
</set>

分享到:
评论

相关推荐

    hibernate inverse和cascade的详细讲解

    hibernate inverse和cascade的详细讲解,相当详细全面的对inverse和cascade区别和用法的讲解

    Hibernate中cascade与inverse属性详解

    Hibernate中cascade与inverse属性详解

    Hibernate中Inverse和Cascade的区别.html

    Hibernate中Inverse和Cascade的区别.html

    Hibernate中Cascade和inverse的区别

    Hibernate中Cascade和inverse的区别,讲解的很详细

    Hibernate中cascade与inverse属性详解.doc

    于Hibernate中 cascade 与 inverse 的理解。 您买的Hibernate书是哪一本呢? 孙卫琴的精通Hibernate,还是 深入浅出Hibernate还是那本。。。 我是两本都买了,总体来说还可以,但是,有的地方讲的比较书面化,比如...

    Hibernate中cascade和inverse应用

    Hibernate中cascade和inverse应用

    hibernate 级联(cascade和inverse)一对多

    hibernate 级联(cascade和inverse)一对多,Jar包,数据库建表语句都好了,只要修改一下,数据库配置文件,就可以使用了,使用junit进行测试。

    hibernate集合映射inverse和cascade详解.txt

    hibernate集合映射inverse和cascade详解.txt

    Hibernate_级联关系说明_-_关于cascade和inverse的用法

    inverse Hibernate_级联关系说明_-_关于cascade和inverse的用法

    hibernate

    Hibernate fetch lazy cascade inverse 关键字

    hibernate xml

    Hibernate中cascade和inverse的相关

    J2EE考试复习试题.pdf

    在Hibernate中,cascade属性可以用于级联保存集合中的对象,如果希望Hibernate级联保存集合中的对象,cascade属性应该取save-update值。 知识点14: Session的方法 Session对象提供了多种方法,包括load()、save()、...

    Hibernate学习笔记和资料

    hibernate中一对一,一对多,多对多关系的配置,延迟加载,cascade,inverse hibernate查询方式概述,HQL查询,QBC查询,分页,结果集封装方式 ,高级查询 查询的优化,一级缓存,二级缓存,批量查询,注解方式

    关联映射cascade,inverse讲解

    该源程序代码可以帮助初学者迅速建立hibernate的关联映射的概念,且详细的讲解了cascade和inverse的用法,程序代码进行了详尽的描述,通俗易懂,容易上手

    hibernate 3中的缓存小结

    &lt;set name="products" table="products" cascade="all" inverse="true"&gt; &lt;!-- Hibernate只会缓存对象的简单属性的值, 要缓存集合属性,必须在集合元素中也加入子元素 而Hibernate仅仅是把与当前持久对象关联的...

    精通hibernate:对象持久化技术孙卫琴第二版part2

    本章介绍一对多关联关系的映射方法,重点介绍inverse属性和cascade属性的用法。本章还将介绍通过Hibernate API来保存、修改和删除具有关联关系的对象的方法。 7.1 建立多对一的单向关联关系 148 7.1.1 [many-to-...

    Hibernate注释大全收藏

    Hibernate注释大全收藏 声明实体Bean @Entity ...如果没有@MappedSuperclass 注解,则父类中属性忽略,这是 Order 实体 Bean 只有 id 一个属性。 映射实体Bean的关联关系 一对一 使用 @OneToOne...

    hibernate总结

    i. 如果不加fetch关键字,则hibernate不会抓取关系属性,但会遍历关系属性所对应的表 ii. 不加fetch关键字时,select 要指定返回的对象,否则它要返回数组 iii. 条件:持久化类之间有关系属性映射 Hibernate级联...

    精通Hibernate:对象持久化技术第二版part3

    本章介绍一对多关联关系的映射方法,重点介绍inverse属性和cascade属性的用法。本章还将介绍通过Hibernate API来保存、修改和删除具有关联关系的对象的方法。 7.1 建立多对一的单向关联关系 148 7.1.1 [many-to-...

Global site tag (gtag.js) - Google Analytics