`
hjs482
  • 浏览: 47894 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

hibernate 中lazy、inverse、cascade属性

阅读更多


在hibernate中一对多关联时会经常用到inverse和cascade属性 ,
inverse 有两个值 true ,false  ;如果设置为true 则表示对象的状态变化不会同步到数据库 ;设置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

【测试环境】
一对多关系的两张表:boy、girl(一个男孩可以多个女朋友)

boy表结构
Field   Type       
------  -----------
name    varchar(50)  pk
age     varchar(50)

girl表结构
Field   Type       
------  -----------
name    varchar(50)  pk
bf      varchar(50)  fk

ER图



【保存时: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);

在Boy.hbm.xml中设置,然后对boy对象进行保存。

1.Inverse = true,不指定cascade
   cascade的默认值为none, 当对boy进行保存操作时,girl什么都不做. 所以只保存了boy对象, 没有保存girl对象

2.Inverse = true,cascade=all
   boy与girl对象,包扩外键都成功保存。
   (生成3条SELECT语句和4条INSERT语句,一下简称SELECT 3, INSERT 4)

3.Inverse = false,不指定cascade
   报错。因为boy为主控方,负责维护关系,所以在插入boy对象后,会尝试修改并不存在的girl对象。

4.Inverse = false,cascade=all
   boy与girl对象,包扩外键都成功保存。
   (SELECT 4, INSERT 4, UPDATE 3)

   分析:除了4条INSERT语句之外,其他的6条语句是我们为了图方便付出的代价:3条SELECT语句用来判断girl对象是否在数据表中已经存在,3条UPDATE语句是为了维护外键关系

高效率的做法:在Boy.hbm.xml中设置Inverse=true,在Girl.hbm.xml中设置Inverse=false, 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
   可以猜到结果是出错。原因:外键约束错误

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)

Inverse是hibernate双向关系中的基本概念,当然对于多数实体,我们并不需要双向关联,更多的可能会选择单向关联,况且我们大多数人一般采用一对多关系,而一对多双向关联的另一端:多对一的inverse属性是不存在,其实它默认就是inverse=false.从而防止了在一对多端胡乱设置inverse也不至于出错。但是inverse设置不当确实会带来很大的性能影响,这点是我们必须关注的。

这篇文章已经详细分析了inverse设置不当带来的影响:

http://www.hibernate.org/155.html

看了这篇文章,还是很有必要再写下一些总结的:

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建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。

看下面的多对多的定义大家更会清楚”多对多“与“一对多”的关系:其中我们注意<many-to-many />标签的特点就知道,它是定义了一个多对多关系,而不是<one-to-many/>。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"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

    根据提供的文件信息,我们可以深入探讨Hibernate框架中的几个关键概念,特别是`fetch`, `lazy`, `cascade`, 和 `inverse`关键字的使用与理解。这四个概念在处理对象关系映射(ORM)时非常重要,尤其是在Java环境下...

    Hibernate 多表映射关系配置

    - `cascade` 属性可以控制关联对象的级联操作,例如 `cascade="save-update"` 可以让保存或更新一个实体时,同时保存或更新其关联的对象。 以上就是 Hibernate 中的一对多、多对一和多对多关系的配置和使用方法。...

    hibernate结构框架及组要实现类的深入分析

    例如,在一对多关系中,`inverse="true"` 表示由多的一方负责维护关系,这意味着删除一端对象时,不会自动从数据库中删除关联的多端对象。 **Hibernate 核心类介绍** - **Configuration**:读取配置文件并解析 `....

    Hibernate一对多主键关联映射源代码

    在Java的持久化框架Hibernate中,一对多关系(OneToMany)是一种常见的对象关系映射(ORM)映射方式,它模拟了数据库中一个表的一条记录与另一表的多条记录之间的关联。本教程通过源代码的形式,讲解如何在Hibernate...

    Hibernate_h_源码

    7. **inverse属性**:`inverse`属性用于指定维护关系的责任方。如果设置为`true`,子对象将负责维护关系,否则父对象负责。 8. **孤儿删除**:通过`orphanRemoval`属性,我们可以配置当子对象从父对象的集合中移除...

    Hibernate的多对一和一对多操作实例

    `inverse`属性表示是否反向维护关联关系,`lazy`属性控制加载策略,而`cascade`属性则定义了级联操作的行为。 ### 总结 通过上述实例,我们可以清晰地看到在Hibernate框架中如何实现“多对一”和“一对多”的关系...

    Hibernate双向一对多

    4. **inverse属性**:在`@OneToMany`上设置`inverse`为`true`表示被引用的一方负责维护关系,否则由引用的一方维护。 **示例代码** ```java @Entity public class Class { @Id private Long id; @OneToMany...

    hibernate配置要点详谈

    - 注意双方都需要设置`inverse`和`lazy`属性,`cascade`属性只能设为`insert-update`。 - 保存多对多关系时需要同时保存双方,例如`group1.getRoles().add(role1); role1.getGroups().add(group1); session.save...

    hibernate关联映射的作用和常用属性解释

    为了更好地理解和运用Hibernate中的关联映射机制,我们需要深入了解其常用的属性及其作用。 ##### 1. `&lt;class&gt;`元素 - **`name`**:指定类的完整包名,如`com.example.Person`。 - **`table`**:对应数据库中的...

    Hibernate一对多映射配置详解

    2. `inverse`属性:在双向关联中,如果一方负责维护关联,那么这一方的`inverse`属性设为`true`。 3. `fetch`属性:用于指定关联数据的加载策略,如`EAGER`(立即加载)或`LAZY`(延迟加载)。 4. 外键约束:在...

    hibernate set 集合映射

    1. **级联操作**:通过设置`cascade`属性,我们可以让Hibernate自动处理关联对象的保存、更新和删除操作,简化业务逻辑。 2. **懒加载和即时加载**:通过设置`lazy="true"`,集合可以在需要时才从数据库加载,提高...

    JAVA培训-HIBERNATE的集合映射.doc

    在Hibernate映射文件中,`&lt;set&gt;`标签的`name`属性对应于Java对象中的属性名,如这里的`orders`。`inverse`属性用于指定关联的维护方,如果设为`true`,则表明`Order`对象负责维护与`Customer`的关联。`cascade`属性...

    Hibernate 一对多、多对一、级联、加载、反转

    例如,如果在`User`和`Order`的关系中,我们希望由`User`来控制级联操作,可以将`@OneToMany`的`mappedBy`属性设在`User`上,然后设置`inverse`属性为`true`,使得`User`成为关系的主控方,这样在处理`User`时,级联...

    Hibernate关联关系疑问

    在Hibernate中,可以通过@OneToOne注解来定义,可以是外键约束或主键共享,需要配置fetch属性来决定何时加载关联对象,比如LAZY或EAGER。 2. **一对多关联(OneToMany)**:一个实体可以与多个其他实体关联。这通常...

    角色(使用hibernate映射多对多的关系).zip

    在Java的持久化框架Hibernate中,处理数据库中的多对多关系是一项重要的任务。"角色(使用hibernate映射多对多的关系).zip"这个压缩包文件提供了一个实例,展示了如何利用Hibernate来映射数据库中的多对多关联。在...

    hibernate 经典题目 其中包括很多核心的题目

    `&lt;class&gt;`(表示实体类)、`&lt;id&gt;`(表示主键)、`&lt;property&gt;`(表示普通属性)、`&lt;one-to-one&gt;`(一对一关联)、`&lt;many-to-one&gt;`(多对一关联)、`&lt;set&gt;` 或 `&lt;list&gt;`(多对多关系)、`&lt;key&gt;`(描述外键)、`...

    hibernate的多种映射关系

    这通过 `cascade` 参数在 `@OneToMany` 和 `@ManyToOne` 注解中配置。 7. **懒加载与立即加载 (Lazy Loading vs Eager Loading)** Hibernate 提供了两种加载策略:懒加载(默认)只在需要时加载关联数据,而立即...

    Hibernate3.x关联映射示例

    关联映射还涉及到级联操作(Cascade)、懒加载(Lazy Loading)以及集合的排序和分页等高级特性。级联操作允许我们在操作一个实体时自动处理与其关联的其他实体,如删除一个班级时,是否同时删除所有关联的学生。懒...

    常用 Hibernate 映射配置说明.doc

    通过`set`、`list`、`map`等集合节点实现一对多的关联映射,其中`inverse`属性用于控制关联关系的维护方。 #### 7. 多对一关联 `many-to-one`节点表示多对一的关系,通常涉及外键引用。 #### 8. 多对多关联 `...

Global site tag (gtag.js) - Google Analytics