`
cui09
  • 浏览: 116581 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
最近访客 更多访客>>
社区版块
存档分类
最新评论

彻底明白Hibernate中的Inverse

阅读更多

以前写HBM,用一对多或多对多的时候默认总是加上“inverse=true”。当时想法很简单就是由双方来维护之间的关联关系。今天才终于明白inverse的真正含义了!

其实inverse不复杂,但是要真正明白还是要稍微看一下源码。inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系,说白了就是hibernate如何生成Sql来维护关联的记录!举个最简单的一对多父子关系。那么代码就写成:

父亲中的关系映射
{set name="children" lazy="true" inverse="true"}
      {key column="parent_id"/}
      {one-to-many class="test.Child"/}
{/set}

儿子中关系映射
{many-to-one name="parent" column="parent_id" not-null="true"/}


Parent p = new Parent();
Child c = new Child();
c.setParent(p);  //维护父子之间关系
p.getChildren().add(c);

session.save(p);
session.flush();

注意:{many-to-one}总是设成“inverse=false”的,而且这个属性在Mapping中是不存在的!

这样运行的下来的结果就是:

Hibernate: insert into parent (id) values (?)
Hibernate: insert into child (parent_id, id) values (?, ?)

那么假如c.setParent(p)注释掉,结果就是:

Hibernate: insert into parent (id) values (?)

比较结果显而易见!此外,inverse还有一个重要特点就是会优化Sql。(具体可以把SHOW_SQL这个属性打开,然后观察一下就知道了)

接下来再看看update,还是父子的例子:

Parent p = (Parent) session.load(Parent.class, parentId);
Parent p2 = (Parent) session.load(Parent.class, parentId2);
       
c = (Child) session.find(
            "from Child as child where child.parent = ?",
            p, Hibernate.entity(Parent.class)).get(0);

// 改变儿子c的关系
p.getChildren().remove(c);
p2.getChildren().add(c);
c.setParent(p2);

这样运行下来的结果就是:

Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2
Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )

Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?

Hibernate: update child set parent_id=? where id=?(正确更新了)

那么根据上面的结论,关系应该是由“inverse=false”方来维护的,那么我把代码改成:

Parent p = (Parent) session.load(Parent.class, parentId);
Parent p2 = (Parent) session.load(Parent.class, parentId2);
       
c = (Child) session.find(
            "from Child as child where child.parent = ?",
            p, Hibernate.entity(Parent.class)).get(0);

//p.getChildren().remove(c);
//p2.getChildren().add(c);
c.setParent(p2);

这样运行下来的结果:

Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2
Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )

Hibernate: update child set parent_id=? where id=?

比较结果很明显,少了父加载儿子的过程,乍看下是成功更新了。实际上,结果和DB是不一致的。(原因很简单就是父亲p的children并没有被更新)

那么反过来改一下:

Parent p = (Parent) session.load(Parent.class, parentId);
Parent p2 = (Parent) session.load(Parent.class, parentId2);
       
c = (Child) session.find(
            "from Child as child where child.parent = ?",
            p, Hibernate.entity(Parent.class)).get(0);

p.getChildren().remove(c);
p2.getChildren().add(c);
//c.setParent(p2);

这样结果就成了:

Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2
Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? ) //get children

Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?

显而易见,关联更新没有被执行(更新是由“inverse=false”方负责的,而这里恰恰被注释了)。

 

大多数情况下,很少使用“inverse=false”,但是我还是想仔细研究一下(这样可以更加理解“inverse=true”)。 ^_^
为什么很少使用“inverse=false”?原因很简单之前也提到过,就是不会对双向关系进行优化。
 
还是来看一个父子的例子:
 
父亲中的关系映射
{set name=children lazy=true inverse=false}
      {key column=parent_id/}
      {one-to-many class=test.Child/}
{/set}
 
儿子中关系映射
{many-to-one name=parent column=parent_id not-null=true/}
 
代码:
 
Parent p = new Parent();
Child c = new Child();
p.getChildren().add(c);
c.setParent(p);
session.save(p);
session.save(c);
session.flush();
 
结果:
 
Hibernate: insert into parent (id) values (?)
Hibernate: insert into child (parent_id, id) values (?, ?)
Hibernate: update child set parent_id=? where id=?
 
看到这里就应该明白我之前为什么说“inverse=true”会优化Sql了吧!还有之前也说过是由“inverse=false”来维护关系了,那这里就是由父亲来维护了。假设我在save(p)和save(c)之间掉flush(),结果又会是如何?事实上,是不可以这么做的!因为父亲负责维护关系,如果我在之间加入了flush(),那么就是无法关联更新了(父亲需要一个已经持久化的儿子来触发关联更新)
 
接下来再来看看update:
 
Parent p = (Parent) session.load(Parent.class, parentId);
Parent p2 = (Parent) session.load(Parent.class, parentId2);
       
c = (Child) session.find(
            "from Child as child where child.parent = ?",
            p, Hibernate.entity(Parent.class)).get(0);
p.getChildren().remove(c);
p2.getChildren().add(c);
c.setParent(p2);
 
结果:
 
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=?    //get parent 1
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=?    //get parent 2
Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )
//get first child for parent 1
 
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
 
Hibernate: update child set parent_id=? where id=?               // child.setParent
Hibernate: update child set parent_id=null where parent_id=?     //remove
Hibernate: update child set parent_id=? where id=?               // add
 
结果说明当设成“inverse=false”时,关系是由父亲和儿子来维护的。这种效率和之前我说的“inverse=true”低很多。
 
那么关系是由父亲来维护的,我又把代码改了一下:
 
Parent p = (Parent) session.load(Parent.class, parentId);
Parent p2 = (Parent) session.load(Parent.class, parentId2);
       
c = (Child) session.find(
            "from Child as child where child.parent = ?",
            p, Hibernate.entity(Parent.class)).get(0);
p2.getChildren().add(c);
 
结果:
 
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=?    //get parent 1
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=?    //get parent 2
Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )
//get first child for parent 1
 
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
 
Hibernate: update child set parent_id=? where id=?               // add
 
乍看之下对的,但是父亲p和p2的children的状态是不一致的!
分享到:
评论

相关推荐

    Hibernate中Inverse和Cascade的区别.html

    Hibernate中Inverse和Cascade的区别.html

    Hibernate中cascade与inverse属性详解

    Hibernate中cascade与inverse属性详解

    hibernate inverse 个人总结.doc

    在探讨Hibernate的`inverse`属性之前,我们先要理解Hibernate中的对象关系映射(ORM)以及持久化机制。Hibernate是一个流行的Java ORM框架,它允许开发者将数据库操作转换为面向对象的编程模型,使得数据操作更加...

    JavaEE学习笔记之Hibernate表关系之一对多(inverse详解)

    本文将深入探讨Hibernate中的一对多关系,并重点解析`inverse`属性的作用及其应用。 一对多关系是数据库设计中常见的关联类型,例如一个用户可以拥有多个订单,一个班级可以包含多个学生等。在Hibernate中,通过...

    hibernate inverse和cascade的详细讲解

    ### Hibernate Inverse 和 Cascade 的详细讲解 #### 一、引言 在ORM(Object-Relational Mapping)领域,Hibernate作为一款流行的Java持久层框架,它提供了丰富的API和配置选项来帮助开发者实现对象与数据库表之间...

    Hibernate中cascade和inverse应用

    在 Hibernate 框架中,`cascade` 和 `inverse` 是两个重要的概念,它们主要用于管理对象之间的持久化关系,特别是涉及到一对一(one-to-one)、一对多(one-to-many)和多对多(many-to-many)关系时。这两个属性都...

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

    在Hibernate中,`inverse`属性主要用于多对一或一对多的关系中,用于指定哪一方负责维护关系。当两个实体之间存在关联时,如果一方的集合变更,那么另一方的实体可能也需要更新。这时,`inverse`属性就变得尤为重要...

    hibernate 级联(cascade和inverse)一对多

    在Java的持久化框架Hibernate中,级联操作(Cascade)和反转(Inverse)是两个重要的概念,它们主要用于管理对象关系模型中的关联关系。在一对多的关系中,这些特性可以帮助简化数据操作,提高代码的可读性和维护性...

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

    在探讨Hibernate框架中的级联操作(cascade)与控制权反转(inverse)之前,我们需要先对Hibernate有一个基本的理解。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用提供了一种将对象模型映射到...

    Hibernate学习笔记和资料

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

    inverse=true的总结

    综上所述,“inverse=true”是Hibernate中一个关乎数据一致性与性能的重要配置。理解并恰当运用它,可以有效地优化ORM框架的使用,提高代码质量,并减少潜在的数据库一致性问题。在实际项目开发中,需要根据业务需求...

    Hibernate 简单 PPT 总结

    在Hibernate中,`inverse`属性是一个关键的概念,它用于定义一对多或多对一关系中的维护端。`inverse="true"`表示另一端负责维护关联关系,这在处理关联实体的保存和更新时具有重要意义。例如,如果你有一个学生类和...

    hibernate

    通过上述内容,我们了解了Hibernate中`fetch`, `lazy`, `cascade`, 和 `inverse`的关键概念及其应用场景。这些概念对于高效管理对象之间的关系至关重要,特别是在大型项目中。正确地理解和运用这些特性能够帮助开发...

    inverse 例子

    在Hibernate这个强大的对象关系映射(ORM)框架中,`inverse`属性是一个非常重要的概念,它主要用于管理关联关系的维护责任。在这个例子中,我们将会深入理解`inverse`属性的作用,并通过一个简单的测试案例——`...

    MVC映射inverse

    在Java的ORM框架如Hibernate中,`inverse`属性是一个关键的概念,主要用于管理一对多或多对一关联关系的主键维护。在这个例子中,我们讨论的是`inverse`在一对多双向关联关系中的应用,涉及两个实体类:`Student`和`...

Global site tag (gtag.js) - Google Analytics