`

Hibernate在配置 one-to-many时应该注意的事项

阅读更多

其实配置one-to-many的映射很简单,就是在one所代表的这个类中添加一个集合对象,一般用set,来保存对应的many所代表的那个类的对象,比如,一个person对应多个order,(一个人对应多个订单),那么在person类中添加private Set<Order> order ;这个属性,然后提供get,set方法

然后在Person.hbm.xml中配置:

<set name="order" inverse="true" cascade="all">
   <key column="userid" />
   <one-to-many class="Order" />
</set>

 这样,一个单向的一对多关系就配置完成了,在主程序中新建order对象,保存进set中,再把person.setOrder(set),然后保存order对象,保存person对象就行了。但是这样配置有很大的问题,在数据库中的处理是先是往order表和person表中插入数据,但是order表的外键列插入的是null,然后执行更新语句,更新order表的外键列,把它设置成对应的personid

如下控制台输出的信息:(里面有张表是userinfo而不是personinfo)

Hibernate: insert into USERINFO (username, password, userid) values (?, ?, ?)
Hibernate: insert into ORDERINFO (product, oid) values (?, ?)
Hibernate: insert into ORDERINFO (product, oid) values (?, ?)
Hibernate: insert into ORDERINFO (product, oid) values (?, ?)
Hibernate: update ORDERINFO set USERID=? where oid=?
Hibernate: update ORDERINFO set USERID=? where oid=?
Hibernate: update ORDERINFO set USERID=? where oid=?

这样操作的话性能就很不好了,

如果设置双向一对多关联,那么就很好了,就是在order类中加一个属性private Person person,然后提供get,set方法,然后在Order.hbm.xml中配置

<many-to-one name="person" class="Person" column="personid" />,然后在主程序中,order.set(person),要设置值(控制关联关系),其他的和上面的一样,这样

控制台输出信息如下:

Hibernate: insert into USERINFO (username, password, userid) values (?, ?, ?)
Hibernate: insert into ORDERINFO (product, USERID, oid) values (?, ?, ?)
Hibernate: insert into ORDERINFO (product, USERID, oid) values (?, ?, ?)
Hibernate: insert into ORDERINFO (product, USERID, oid) values (?, ?, ?)

就只有4条插入语句在操作数据库了。

 

关于双向一对多的操作注意一下几点:(引用自李刚的JAVAEEssh整合开发那本书)

1.先持久化one的对象

2.先设置one和many的关联关系,在保存many对象,否则还是会出现先插入,然后再更新的重复操作数据库的现象

3.不要通过one的那一端来控制关联关系,可以设置set的inverse=“true”来控制,或者在主程序中不通过设置set来关联两个类

(inverse的意思是反转,用来设置关系哪一方是拥有者owner,由他来维护这个关系。

作用是在一对多双向关联关系中使一方放弃维护到对方的关系(抽象)。其实就是减少重复执行多余的SQL语句 )

inverse="false" 是默认情况,此时没有反转,则 Set/Collection 关系由包含它的“一”这一方来维;

 

inverse="true" 时,表示 Set/Collection 关系由另一方来维护,由不包含这个关系的一方来维护这个关系,所以才称为“反转”了

 

实例分析:

以Student(学生)和Class(班级)为例,它们之间的关系为一对多的关系,即一个学生只能属于一个班级,一个班级可以包含多个学生。

Class班级:
Class Class{
  private int id;
  private String name;
  private Set students = new HashSet();
  //省略getter()和setter()方法
}
 Student学生:
Class Student{
  private int id;
  private String name;
  private Class class;
  //省略getter()和setter()方法
}
 Class类的映射文件:
<class name="Class" table="CLASS">
   <id name="id" type="int" column="ID">
     <generator class="native" />  
   </id>
   <property name="name" type="string" column="NAME" />
   <set name="students" table="STUDENT" cascade="save-update" inverse="false">
     <key column="CLASS_ID" />
     <one-to-many class="Student" />
   </set>
</class>
Student类的映射文件:
<class name="Student" table="STUDENT">
   <id name="id" type="int" column="ID">
      <generator class="native" />  
   </id>
   <property name="name" type="string" column="NAME" />
   <many-to-one name="class" column="CLASS_ID" class="Class" cascade="save-update" /> 
</class>
 
STUDENT表中存在一个名为CLASS_ID的字段,它和CLASS表中的ID字段是主外键关系。那个inverse属性就是用来规定是由谁(Student或Class)来维护这个主外键关系的。

inverse的默认值为false。 在处理逻辑代码中,如下:
Class c1 = new Class();
c1.setName("一班");
Student s1 = new Student();
Student s2 = new Student();
s1.setName("Jason");
s2.setName("Tom");
c1.getStudents().add(s1);
c2.getStudents().add(s2);
s1.setClass(c1);
s2.setClass(c1);   //注释1
session.save(c1);

上面的代码会使Hibernate执行五条SQL语句,其中前三条是insert插入语句,后两条是update更新语句。插入就不用说了,那么为什么还要有更新语句呢?这是因为Class类映射文件的<set>元素中指定了inverse="false",这就告之Hibernate:STUDENT表与CLASS表的主外键关系是由Class类来维护的。当执行save后,执行了三条insert语句,这三条语句中的后两条是插入到STUDENT表的,它们的CLASS_ID字段是通过s1.getClass().getID()取出的,假如我将上面“注释1”处修改为s2.setClass(c2);(c2是另一个Class对象,可能是持久化对象),这样,主外键关系不就乱了吗。为了保证主外键关系,Hibernate在这种情况下会再执行两条update语句来更改STUDENT表中两个新插入记录的CLASS_ID字段,当然,这时CLASS_ID字段的取值是从c1对象中直接取得,而不再是s1.getClass().getID()方式了。
如果我们将Class类映射文件的<set>元素中的inverse属性修改为true,这就是告诉Hibernate:Class类不维护主外键关系了,这个任务就交给了Student类。于是,我们再执行上面的代码,Hibernate就会只执行三条insert语句,而不会执行任何update语句。因为Hibernate会通过Student类的s1.getClass().getID()和s2.getClass().getID()来确定CLASS_ID字段的值。
故,为了节省数据库资源,省却不必要的update语句,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。
打个比方:在一个公司中,是老板认识所有的员工容易,还是所有员工认识老板容易?
分享到:
评论

相关推荐

    Hibernate one-to-many / many-to-one关系映射

    "Hibernate one-to-many / many-to-one关系映射"是两个基本的关系类型,用于表示实体间的关联。在这个主题中,我们将深入探讨这两种关系映射的原理、配置和实际应用。 一、一对一(one-to-one)与一对多(one-to-...

    (4)Hibernate中的many-to-one和one-to-many关系

    在实际应用中,我们经常需要建立双向关联,即在many-to-one的一端和one-to-many的一端都可以访问到对方。例如,班级可以获取其所有学生,而学生也可以知道他们所属的班级。在双向关联中,一方(通常是one-to-many的...

    hibernate学习5之one-to-many双向关联.docx

    在配置双向一对多关联时,我们通常在"多"一端(这里是`Student`)的集合属性上使用`&lt;many-to-one&gt;`标签,将`Classes`对象映射到数据库中的外键。同时,在"一"端(`Classes`)使用`&lt;set&gt;`标签,表示班级可以包含多个...

    hibernate many-to-one(多对一)及 cascade(级联).doc

    在Hibernate中,可以通过 `&lt;many-to-one&gt;` 或者 `&lt;one-to-many&gt;` 标签中的 `cascade` 属性来指定这种行为。 #### 代码示例解析 在提供的代码示例中,`&lt;many-to-one&gt;` 标签中包含了 `cascade` 属性的注释示例,但是...

    hibernate one-to-one 一对一唯一外键关联映射_单向 and 双向

    在Hibernate中,一对一唯一外键关联映射可以通过 `&lt;many-to-one&gt;` 标签来配置。例如,以下是Person实体与IdCard实体的一对一唯一外键关联映射配置: ```xml &lt;many-to-one name="idCard" column="card_id...

    Hibernate one-to-many-annotation

    在Hibernate中,`one-to-many`关系是常见的实体间关系之一,表示一个实体可以与多个其他实体相关联。本文将深入探讨`Hibernate one-to-many`注解的使用和实现细节。 ### 一、`@OneToMany`注解概述 `@OneToMany`...

    Hibernate-one-to-many

    同时,`Account.hbm.xml`中的`many-to-one`元素将`column`属性设置为`FID`,表示通过`FID`字段关联到`User`实体。 #### 测试场景解释 在测试场景中,我们创建了一个`User`对象和一个`Account`对象,并在`User`对象...

    Hibernate应用例子many-to-many

    本示例将详细讲解如何在Hibernate中实现多对多(many-to-many)的关系映射。 在数据库设计中,多对多关系是指两个实体之间存在多个关联,比如学生和课程的关系,一个学生可以选修多门课程,一门课程也可以被多个...

    hibernate one-to-many 单/双向关联映射配置心得

    本文主要关注Hibernate中的一个核心概念——一对一(One-to-One)、一对多(One-to-Many)和多对一(Many-to-One)关联映射,特别是关于“一到多”单向和双向关联映射的配置心得。 首先,让我们了解“一到多”关联...

    Hibernate one to many(many to one) 配置

    标题"Hibernate one to many(many to one) 配置"涉及到的是关系型数据库在Java中的持久化框架Hibernate中的两种关联映射关系:一对一(One-to-One)和多对一(Many-to-One)。在数据库设计中,这种关系很常见,例如...

    Hibernate Mapping Many-to-One 实例 内附源代码及附件下载

    这种关系在Hibernate中通过`&lt;many-to-one&gt;`标签来配置。下面我们将深入探讨这个概念。 首先,我们需要定义两个实体类,一个是`Department`,另一个是`Employee`。`Department`类将包含对`Employee`对象的引用,而`...

    Hibernate Tutorial 04 (Many-to-one and One-to-one Association

    为了使用 `publisher` 属性,我们需要在 `Book` 类的 Hibernate 映射文件中添加 `&lt;many-to-one&gt;` 映射。这将在 `BOOK` 表中添加一个名为 `PUBLISHER_ID` 的列,并存储关联出版商的 ID。 ```xml &lt;!-- 其他属性的...

    hibernate many to one

    在处理Many-to-One关系时,注意避免N+1查询问题,即在循环遍历集合时,每次获取关联对象都会发起一次SQL查询。通过批量获取或预先加载关联数据可以优化性能。 总结,Hibernate的Many-to-One关系映射是数据库关系...

    Hibernate实现many-to-many的映射关系

    3. 在对应的映射文件中,使用`&lt;set&gt;`和`&lt;one-to-many&gt;`或`&lt;many-to-one&gt;`元素配置映射关系。 4. 如有必要,可以考虑将多对多关系转换为一对多,以优化性能和操作性。 理解并熟练掌握这些概念和实践,将有助于在使用...

    hibernate中one2many映射

    在Java的持久化框架Hibernate中,One-to-Many映射是一种常见的关系映射方式,它表示一个实体(比如一个用户)可以与多个其他实体(比如用户的订单)进行关联。在这个场景下,"用户"是一方,称为"One","订单"是另...

    NHibernate One-to-Many一对多映射-xxlinux_com

    在数据库世界中,一对多(One-to-Many)关系是一种常见的关联类型,其中一个表(父表)可以与多个其他表(子表)相关联。在NHibernate中,配置这种映射关系对于理解和使用ORM至关重要。 一对多关系意味着一个实体...

    Hibernate的配置详解

    这里我们重点关注一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)关系。 1. 一对一关系(One-to-One): - 主键关联:一个实体对象对应另一个实体对象的一个实例,通常通过主键共享。例如,...

    many-to-one 配置详解

    many-to-one 配置详解 讲的很清楚 适合新手 值得下载

    学习hibernate必看ppt--总结的很全面

    2. **关联映射**:Hibernate支持多种关系映射,包括一对一(One-to-One)、一对多(One-to-Many)、多对一(Many-to-One)和多对多(Many-to-Many)。这部分可能详细解释了这些关系的配置,以及在Java对象和数据库表...

    Hibernate之第3解之-hibernate_hibernate_many2one_1

    在Hibernate配置文件或JPA注解中指定外键字段,即可在数据库创建时自动创建外键约束。 6. **查询优化**: 当处理大量关联数据时,需要关注N+1查询问题。如果不对关联关系进行合理优化,可能会导致性能瓶颈。使用...

Global site tag (gtag.js) - Google Analytics