Chinaunix首页 | 论坛 | 博客
  • 博客访问: 742383
  • 博文数量: 225
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2722
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-03 17:32
文章分类

全部博文(225)

文章存档

2019年(7)

2018年(16)

2017年(1)

2016年(26)

2015年(41)

2014年(15)

2013年(119)

我的朋友

分类: Java

2013-08-28 15:13:15

首先,来看inverse和cacade的取值有哪些..
1. cascade 有五个选项 分别是: all ,delete ,none,save-update,delete-orphan ;
2. inverse 有两个值 true ,false
这几个值各是什么呢?
cascade的五个值:
        all:所有情况下均进行关联操作,即save-update + delete.
        none:所有情况下均不进行关联操作。这是默认值。
        save-update:在执行save/update/saveOrUpdate时进行关联操作。
        delete:在执行delete时进行关联操作。
        delete-orphan: 当save/update/saveOrUpdate时,相当于save-update;删除时,相当于delete
还有个 all-delete-orphan :是当对象图中产生孤儿节点时,在数据库中删除该节点 。//不太明白

inverse:ture 表示主控权交给关联类来执行
         false默认值 ,由自己来行驶主控权

 inverse属性默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student,  Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表 现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对 TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指 定的是"谁"维护关系,那个在插入或删除"谁"时,就会处发对关系表的操作。前提是"谁"这个对象已经知道这个关系了,就是说关系另一头的对象已经set 或是add到"谁"这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在关系的一头,如Student中的bag或set中用了inverse="true"时,那就代表关系是由另一关维护的(Teacher)。就是说当这插入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的操作。所以,当关系的两头都用inverse="true"是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是inverse= "false"或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。

  在一对多关系中inverse就更有意义了。在多对多中,在哪端inverse="true"效果差不多(在效率上)。但是在一对多中,如果要一方维护关系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象(注意:这里所指的有关系一般是指的设置多方的ID属性,使之与一方的关联在一起)。而如果让"多"方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。当然这时也要遍历"多"方的每一个对象显示的操作修关系的变化体现到DB中。不管 怎样说,还是让"多"方维护关系更直观一些。
    (1)对one-to-many而言,改变set,会让hibernate执行一系列的update语句,不会delete/insert数据
    (2)对many-to-many而言,改变set,只修改关系表的数据,不会影响many-to-many的另一方。
    (3)虽然one-to-many和many-to-many的数据库操作不一样,但目的都是一个:维护数据的一致性。   
 

测试:
一对多关系的两张表:boy、girl(一个男孩可以多个女朋友)
boy表结构
Field   Type        
------  -----------
name    varchar(50)  pk
age     varchar(50)
girl表结构
Field   Type        
------  -----------
name    varchar(50)  pk
bf      varchar(50)  fk

【保存时:Inverse与cascade】
创建三个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);
  session.save(boy);
在Boy.hbm.xml中设置,
1.Inverse = true,不指定cascade 既为none
   cascade的默认值为none, 当对boy进行保存操作时,girl什么都不做. 所以只保存了boy对象, 没有保存girl对象
2.Inverse = true,cascade=all (由多方来维护关系,那么不需要update,因为它关系就在它那儿)
   boy与girl对象,包扩外键都成功保存。只不过girl表中的对应的id是null
   (SELECT 3, INSERT 4)
3.Inverse = false,不指定cascade,既为none
   报错。因为boy为主控方,负责维护关系,在维护关系是发现并不存在girl记录,所以不能建立关系。
4.Inverse = false,cascade=all   (由一方维护关系,那么会产生update)
   boy与girl对象,包扩外键都成功保存。
   (SELECT 3, INSERT 4, UPDATE 3)
   分析:除了4条INSERT语句之外,其他的6条语句是我们为了图方便付出的代价:3条SELECT语句用来判断girl对象是否在数据表中已经存在,3条UPDATE语句是为了维护外键关系
高效率的做法:在Boy.hbm.xml中设置Inverse=true,在Girl.hbm.xml中设置cascade=all,然后保存三个girl对象
(SELECT 1, INSERT 4)
   高效率的代价就是保存的时候比较麻烦
【删除时:Inverse与cascade】
希望通过删除boy,也将3个girl对象删除。程序中先查出boy对象,然后进行删除
  -----------------------------------------
  Boy boy = (Boy) s.get(Boy.class, "tom");
  s.delete(boy);
  -----------------------------------------
同样在Boy.hbm.xml中进行设置
1.Inverse = true  cascade = none
   可以猜到结果是出错。原因:外键约束错误,他没有维护关系,所以引起外间冲突
2.Inverse = false  cascade = none                
   boy删除,girl表中外键变为null,没有删除记录 ;  
(UPDATE 1, DELETE 1)
3.Inverse = false, cascade = all
          全部删除  ;在删除有外键的从表时,先把从表外键置为null,然后删除主表记录,最后根据从表主键删除所有相关从表记录
   (UPDATE 1, DELETE 4)
4.Inverse = true, cascade = all
          全部删除
   (DELETE 4)
Inverse是hibernate双向关系中的基本概念,当然对于多数实体,我们并不需要双向关联,更多的可能会选择单向关联,况且我们大多数人一般采用一对多关系,而一对多双向关联的另一端:多对一的inverse属性是不存在,其实它默认就是inverse=false.从而防止了在一对多端胡乱设置inverse也不至于出错。但是inverse设置不当确实会带来很大的性能影响,这点是我们必须关注的。

看了这篇文章,还是很有必要再写下一些总结的:
1)inverse中提及的side其实是指一个类或者表的概念,双向关联其实是指双方都可以取得对方的应用。
2)维护关系这个名词还是稍显模糊或者晦涩。我们一般说A类或者A表(这里的表的是指多对多的连接表)有责任维护关系,其实这里的意思是说,我在应用在更新,创建,删除(读就不用说了,双向引用正是为了方便读而出现)A类或者A表时,此时创建的SQL语句必须有责任保证关系的正确修改。
3)inverse=false的side(side其实是指inverse=false所位于的class元素)端有责任维护关系,而inverse=true端无须维护这些关系。
4)我们说inverse设立不当会导致性能低下,其实是说inverse设立不当,会产生多余重复的SQL语句甚至致使JDBC exception的throw。这是我们在建立实体类关系时必须需要关注的地方。一般来说,inverse=true是推荐使用,双向关联中双方都设置 inverse=false的话,必会导致双方都重复更新同一个关系。但是如果双方都设立inverse=true的话,双方都不维护关系的更新,这也是不行的,好在一对多中的一端:many-to-one默认是inverse=false,避免了这种错误的产生。但是对多对就没有这个默认设置了,所以很多人经常在多对多的两端都使用inverse=true,结果导致连接表的数据根本没有记录,就是因为他们双方都没有责任维护关系。所以说,双向关联中最好的设置是一端为inverse=true,一端为inverse=false。一般inverse=false会放在多的一端,那么有人提问了, many-to-many两边都是多的,inverse到底放在哪儿?其实hibernate建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。

阅读(2947) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~