一、基本概述

在表中的一对多,是使用外键关联,通过一张表的一个键另一个表的外键来建立一多关系;而在类中表示为一个类中有一个集合属性包含对方类的很多对象,而在另一个类中,只包含前述类的一个对象,从而实现一对多关系的建立!

而在Hibernate中采用的是Set类型集合,使用<one-to-many>和<many-to-one>来实现。

对于一对多的映射关系可以分为两种情况:单向映射和双向映射。

单向映射:只能从一方访问到另一方,无法反向访问。

双向映射:双方都可以通过映射访问到对方。

这里以双向映射为例,单向映射只需在一端的配置文件和代码中删除相应的代码块即可。

二、实例演示(双向映射)

1、模型抽象

这里以 Customer 和 Order 为例: 一个客户能发出多个订单, 而一个订单只能属于一个客户. 从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联。



Customer.java

package com.chen.one2many;

import java.util.HashSet;
import java.util.Set; public class Customer {
private Integer customerID;
private String customerName;
//持有一个order的集合对象,表示一个客户customer可以有多个订单order
Set<Order> orders=new HashSet<>(); public Integer getCustomerID() {
return customerID;
}
public void setCustomerID(Integer customerID) {
this.customerID = customerID;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
} }

Order.java

package com.chen.one2many;

public class Order {
private Integer orderID;
private String orderName; //持有一个Customer的引用,一个订单order只能属于一个用户customer
private Customer customer; public Integer getOrderID() {
return orderID;
}
public void setOrderID(Integer orderID) {
this.orderID = orderID;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
} }

2、配置相关xml文件

Customer.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-10 10:28:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.chen.one2many.Customer" table="CUSTOMERS">
<id name="customerID" type="java.lang.Integer">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property>
<!--利用set标签完成映射
name:该集合对应的属性名 orders
table:关联的另一端对应的表名 ORDERS
cascade 级联关系,当保存或更新时会级联保存与这个Customers对象相关联的所有Orders对象
inverse=true是将控制权抛出(给Order) -->
<set name="orders" table="ORDERS" cascade="save-update" inverse="true">
<key column="CUSTOMER_ID"></key><!-- 表字段 -->
<one-to-many class="com.chen.one2many.Order"/><!-- 关联的类 -->
</set>
</class>
</hibernate-mapping>

Order.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-3-10 10:28:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.chen.one2many.Order" table="ORDERS">
<id name="orderID" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<!--使用 many-to-one 来映射多对一的关联关系
name: Order(也就是一对多中多的这一端)中持有的另一端的属性名,也就是customer
class: 上一个属性所对应的类
column: 映射的外键名,也就是另一个表的主键 -->
<many-to-one name="customer" class="com.chen.one2many.Customer"
column="CUSTOMER_ID"></many-to-one>
</class>
</hibernate-mapping>

Hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory> <!-- Hibernate 连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://192.168.1.148:3306/hibernate5</property> <!-- Hibernate 的基本配置 -->
<!-- Hibernate 使用的数据库方言,为了使mysql自动生成数据表
对于mysql5.x使用如下设置 -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <!-- 运行时是否打印 SQL -->
<property name="show_sql">true</property> <!-- 运行时是否格式化 SQL -->
<property name="format_sql">true</property> <!-- 生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property> <!-- 设置 Hibernate 的事务隔离级别 -->
<property name="connection.isolation">2</property> <!-- 删除对象后, 使其 OID 置为 null -->
<property name="use_identifier_rollback">true</property> <!-- 配置 C3P0 数据源 -->
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property> <property name="c3p0.idle_test_period">2000</property>
<property name="c3p0.timeout">2000</property> <property name="c3p0.max_statements">10</property> <!-- 设定 JDBC 的 Statement 读取数据的时候每次从数据库中取出的记录条数 -->
<property name="hibernate.jdbc.fetch_size">100</property> <!-- 设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小 -->
<property name="jdbc.batch_size">30</property> <!-- 需要关联的 hibernate 映射文件 .hbm.xml -->
<mapping resource="com/chen/one2many/Customer.hbm.xml"/>
<mapping resource="com/chen/one2many/Order.hbm.xml"/> </session-factory>
</hibernate-configuration>

3、编写测试方法

HibernateTest.java

package com.chen.one2many;

import java.util.Iterator;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder; public class HibernateTest {
private static SessionFactory sessionFactory;
private static Session session;
private static Transaction transaction; //定义事务初始化函数
public static void init(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry =
new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession();
transaction = session.beginTransaction();
} //定义事务结束时的处理函数
public static void doit(){
transaction.commit();
session.close();
sessionFactory.close();
} //编写自己的处理过程
public static void test(){
//初始化基本信息:一个客户chen有两个订单book和food
Customer customer=new Customer();
customer.setCustomerName("chen");
Order order1=new Order();
order1.setOrderName("book");
Order order2=new Order();
order2.setOrderName("food"); //设置对应关系(双向映射) //关联customer
order1.setCustomer(customer);
order2.setCustomer(customer);
//关联order
customer.getOrders().add(order1);
customer.getOrders().add(order2); //因为配置文件中cascade="save-update",所以保存customer时会级联保存与之相关的order
session.save(customer); //从order表中获取customer
Order orderResult=(Order) session.get(Order.class, 1);
String ordername=orderResult.getOrderName();
String customername=orderResult.getCustomer().getCustomerName();
System.out.println(ordername+" is owned by "+customername); //从customer表中获取order
Customer customerResult=(Customer) session.get(Customer.class, 1);
Set<Order> set=customerResult.getOrders();
System.out.println(set.size());
for (Iterator iterator2 = set.iterator(); iterator2.hasNext();) {
Order order = (Order) iterator2.next();
System.out.println(order.getOrderName());
}
}
public static void main(String[] args) {
HibernateTest.init();
HibernateTest.test();
HibernateTest.doit();
System.out.println("完成---------");
} }

4、运行结果

数据表

customers

orders

运行窗口显示

三、单向一对多映射与双向映射原理相同,只是把其中一端的配置文件和代码进行删减即可。具体而言:

1、单向order--->customer。即order中持有customer的一个引用。

order端的代码和配置文件不用改。把customer代码中的order集合代码删除,配置文件中的set标签内容删除。

2、单向customer---->order。不推荐。操作复杂

一般推荐使用order(多的一端)持有customer(一的一端)的引用,这样可以减小维护代价。

四、inverse 属性详解

在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系。inverse = false 的为主动方,inverse = true 的为被动方即交出控制权, 由主动方负责维护关联关系。在没有设置 inverse=true 的情况下,父子两边都维护关联关系 。

在 1-N关系中,将 N 方设为主控方将有助于性能改善。在 1-N 关系中,若将 1 方设为主控方会额外多出 update 语句,且插入数据时无法同时插入外键列,因而无法为外键列添加非空约束。

Hibernate表关系映射之一对多映射的更多相关文章

  1. Hibernate表关系映射之一对一映射

    一.数据表的映射关系 在数据库领域中,数据表和数据表之间关系一般可以分为如下几种: 一对一:比如公民和身份证的关系,一个人只有一张身份证,同时每张身份证也仅仅对应一个人! 一对多:比如客户和订单之间的 ...

  2. Hibernate表关系映射之多对多映射

    一.多对多的实现原理 在数据库中实现多对多的关系,必须使用连接表.也就是用一个独立的表来存入两个表的主键字段,通过遍历这张表来获取两表的关联关系. 而在我们的对象中,多对多是通过两者对象类中互相建立对 ...

  3. hibernate(3) —— 关系映射

    hibernate中关系映射指的是实体类与实体类间的关系.和数据库中表与表之间的关系类似,有一对一,多对一,一对多,多对多四种映射关系. 一:一对一映射 两个对象之间是一对一的关系,如人和身份证之间是 ...

  4. Hibernate注解关系映射

    Hibernate Annotation关系映射的几种类型映射用法及使用方法(说明:以前实例的实体是user和role,主键分别是userid和roleid)   1)一对一外键关联映射(单向) @O ...

  5. 详谈Hibernate框架关系映射!

    接触Hibernate也有一小段的时间了,愈发的觉得Hibernate是个神奇的东西,为什么这么说呢?因为你可以不懂一行sql,直接面向对象,就可以将数据直接保存到数据库去!! 你还可以保存一个对象, ...

  6. hibernate 实体关系映射笔记

    @经常使用属性说明:     @Entity:实体类     @Table:指定相应数据表     @Id:主键,使用能够为null值的类型,假设实体类没有保存到数据库是一个暂时状态     @Col ...

  7. hibernate对象关系映射( 一对一,一对多,多对一,多对多的单向,双向映射 ——)

    对象之间的关系: 关系映射之间的关系只的是对象之间的关系,并不指数据库表的关系(外键关系)这儿解决的问题是当对象之间的关系之一时,数据库表该如何映射,编程上如何对待. 一对一(主键关联,和单向的外键关 ...

  8. Hibernate 对象关系映射文件

    简介: POJO 类和关系型数据库之间的映射可以用一个 XML 文档来定义 通过 POJO 类的数据库映射文件,Hibernate 可以理解持久化类和数据表之间的对应关系,也可以理解持久化类属性与数据 ...

  9. Hibernate表关系03

    一. 一对多映射 1.基本应用 1.1 准备项目 创建项目:hibernate-02-relation 引入jar,同前一个项目 复制实体(客户).映射.配置.工具类 1.2 创建订单表 表名: t_ ...

随机推荐

  1. 【HDU3507】Print Article(斜率优化DP)

    单调队列DP复出练手题 朴素方程dp[i]=min(dp[j]+(s[i]-s[j-1])^2+m 你懂得 ..]of int64; a,q:array[..]of longint; n,m,i,t, ...

  2. Git基础篇【转】

    转自:https://i.cnblogs.com/EditPosts.aspx?opt=1 1.设置名字与邮箱 $ Git config –global user.name “YourName” $ ...

  3. 47深入理解C指针之---指针与硬件

    一.size_t:用于安全表示长度,所有平台和系统都会解析成自己对应的长度 1.定义:size_t类型表示C中任何对象所能表示的最大长度,是个无符号整数:常常定义在stdio.h或stdlib.h中 ...

  4. django中表变更后migrate无效的问题

    问题描述: 已有的model,修改之后,想重新建模,于是将migrations文件夹中除__init__.py之外其他文件都删掉,再次执行以下步骤python manage.py makemigrat ...

  5. andriod 获得应用程序名称

    import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; im ...

  6. 【spring cloud】spring cloud服务发现注解之@EnableDiscoveryClient与@EnableEurekaClient

    spring cloud服务发现注解之@EnableDiscoveryClient与@EnableEurekaClient的区别

  7. 低成本安全硬件(二):RFID on PN532

    引言 鉴于硬件安全对于大多数新人是较少接触的,而这方面又非常吸引我,但是部分专业安全研究设备较高的价格使人望而却步.在该系列中,笔者希望对此感兴趣的读者在花费较少金钱的情况下体会到硬件安全的魅力所在. ...

  8. UVA571 - Jugs(数论)

    UVA571 - Jugs(数论) 题目链接 题目大意:给你A和B的水杯.给你三种操作:fill X:把X杯里面加满水.empty X:把X杯中的水清空.pour X Y 把X的水倒入Y中直到一方满或 ...

  9. poj 2528(区间改动+离散化)

    题意:有一个黑板上贴海报.给出每一个海报在黑板上的覆盖区间为l r,问最后多少个海报是可见的. 题解:由于l r取值到1e7,肯定是要离散化的,但普通的离散化会出问题.比方[1,10],[1,4],[ ...

  10. jQeury入门:遍历

    一旦用jQuery创建一个初始的包装集.你就能深度遍历刚刚选择的包装集. 遍历能够被分为三个基础元件:父级.子级,同级.jQuery为全部这些元件提供丰富易用的方法.注意每个方法都能轻易的传递给字符串 ...