上一篇博文总结了 Hibernate 的一对一的关联关系, 包括基于主键的单向一对一, 基于外键的单向一对一, 基于外键的双向一对一.

  下面咱们说一下 Hibernate 的一对多关联关系.

  其实一对多和多对一是一样的, 一对多反过来想就是多对一了.

Hibernate的一对多可分为:

  1. 单向一对多.

  2. 双向一对多.

OneByOne

  一: 单向一对多

准备工作:

  咱们以 客户(Customer) 和 订单(Order) 的例子来说, 一个客户可以有多个订单, 但是一个订单只能属于一个客户, 这就构成了一对多的关系.

  1. 建立持久化类:

    Customer类:

package com.single.many2one;

public class Customer {

    private Integer id;
    private String name;

    public Customer() {
        super();
    }

    public Customer(String name) {
        super();
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

    Order类:

package com.single.many2one;

public class Order {

    private Integer id;
    private String name;

    private Customer customer;

    public Order() {
        super();
    }

    public Order(String name, Customer customer) {
        super();
        this.name = name;
        this.customer = customer;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

  2. 建立对应的映射文件

    Customer类映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.single.many2one.Customer" table="CUSTOMERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
    </class>
</hibernate-mapping>

    Order类映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.single.many2one">
    <class name="Order" table="ORDERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <many-to-one name="customer" class="Customer">
            <column name="CUSTOMER_ID" />
        </many-to-one>
    </class>
</hibernate-mapping>

  3. 把映射文件加入到 Hibernate 的主配置文件( hibernate.cfg.xml )里

  4. 建立单元测试类

package com.single.many2one;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestHibernate {

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Before
    public void init(){

        sessionFactory = new Configuration().configure().buildSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void distory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }
}

    在上面的持久化类中, 订单(Order)中有对客户(Customer)的引用, 而客户(Customer)不知道订单(Order)的存在.

    1. 测试保存数据:

    @Test
    public void testInsert(){

        Customer customer = new Customer("Mike");

        Order order1 = new Order("O-Mike-01", customer);
        Order order2 = new Order("O-Mike-02", customer);
        Order order3 = new Order("O-Mike-03", customer);

        // 保存的时候要先保存 1 的一端, 然后保存 n 的一端
        // 这样可以避免多出 n 条 update 语句
        session.save(customer);
        session.save(order1);
        session.save(order2);
        session.save(order3);

    }

    为什么反过来保存会多出 n 条update语句, 很简单, 维护关联关系. 如果先保存 order 这个时候, 外键还没有值, 最后插入Customer的时候, 外键有值了, 就会发送update语句来更新Order表的外键值.

    2. 测试查询数据

    @Test
    public void testQuery(){

        // 默认使用懒加载模式, 注意懒加载异常
        Order order = session.get(Order.class, 1);
        System.out.println(order.getName());
        System.out.println(order.getCustomer().getClass().getName());

    }

    默认使用懒加载, 如果想不适用懒加载可以在 <many-to-one> 标签中使用 lazy="false", 来禁用懒加载.

    3. 测试删除数据:

    @Test
    public void testDelete(){

        // 想想都知道, 有外键约束, 肯定不会删除成功.
        Customer customer = session.get(Customer.class, 1);
        session.delete(customer);

    }

    4. 测试更新数据:

    @Test
    public void testUpdte(){

        // 一般不会出现什么问题
        // 作为程序员这样说, 实在是太不负责任了
        // 是我掌握的不够. 以后会继续深入研究的.
        Customer customer = session.get(Customer.class, 1);
        customer.setName("Jerry");
        session.update(customer);

    }

  二: 双向一对多

准备工作:

  咱们还是以客户(Customer)和订单(Order)的例子来说, 与上面不同的是, 现在Customer类中有一个集合(Set)来存放Order对象.

  1. 建立持久化类:

    Customer类:

package com.doubles.one2many;

import java.util.HashSet;
import java.util.Set;

public class Customer {

    private Integer id;
    private String name;

    private Set<Order> orders = new HashSet<>();

    public Set<Order> getOrders() {
        return orders;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

    public Customer() {
        super();
    }

    public Customer(String name) {
        super();
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

    Order类:

package com.doubles.one2many;

public class Order {

    private Integer id;
    private String name;

    private Customer customer;

    public Order() {
        super();
    }

    public Order(String name, Customer customer) {
        super();
        this.name = name;
        this.customer = customer;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

  2. 建立映射文件

    Customer的映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.doubles.one2many">
    <class name="Customer" table="CUSTOMERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!--
            在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系.
            inverse = false 的为主动方
            inverse = true  的为被动方
            由主动方负责维护关联关系
            在没有设置 inverse=true 的情况下, 父子两边都维护父子关系
            在 1-n 关系中, 将 n 方设为主控方将有助于性能改善
            (如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
            在 1-N 关系中,若将 1 方设为主控方会额外多出 update 语句.
            插入数据时无法同时插入外键列,因而无法为外键列添加非空约束.
        -->
        <set name="orders" table="ORDER" inverse="true">
            <!--
                设定与所关联的持久化类对应的表的外键
                column: 指定关联表的外键名, 就是 Order.hbm.xml 中的外键(CUSTOMER_ID)
            -->
            <key column="CUSTOMER_ID" />
            <!--
                设定集合属性中所关联的持久化类
                class: 指定关联的持久化类的类名
            -->
            <one-to-many class="Order" />
        </set>

    </class>
</hibernate-mapping>

    Order的映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.doubles.one2many">
    <class name="Order" table="ORDERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <many-to-one name="customer" class="Customer">
            <column name="CUSTOMER_ID" />
        </many-to-one>

    </class>
</hibernate-mapping>

  3. 把映射文件加入到 Hibernate 的主配置文件( hibernate.cfg.xml )里

  4. 建立单元测试类(略)

  1. 测试保存数据:

    @Test
    public void testInsert() {

        Customer customer = new Customer("Jerry");

        Order order1 = new Order("O-Jerry-01", customer);
        Order order2 = new Order("O-Jerry-02", customer);
        Order order3 = new Order("O-Jerry-03", customer);

        customer.getOrders().add(order1);
        customer.getOrders().add(order2);
        customer.getOrders().add(order3);

        /*
         * 1. 在没有设置 inverse="true" 的情况下
         *      a). 如果先保存 n 的一端, 再保存 1 的一端, 会多出 6 条update语句.
         *      b). 如果先保存 1 的一端, 在保存 n 的一端, 会多出 3 条update语句.
         * 2. 设置了 inverse="true" 的情况下
         *      a). 如果先保存 n 的一端, 再保存 1 的一端, 会多出 3 条update语句.
         *      b). 如果先保存 1 的一端, 再保存 n 的一端, 没有多余的update语句.
         */
        session.save(customer);
        session.save(order1);
        session.save(order2);
        session.save(order3);

    }

    出现 update 语句是因为要维护两个数据表之间的关联关系.

    2. 测试删除数据:

    @Test
    public void testQuery(){

        // 默认使用懒加载
        Customer customer = session.get(Customer.class, 1);
        System.out.println(customer.getName());
        System.out.println(customer.getOrders().getClass().getName());
        //上一语句打印: org.hibernate.collection.internal.PersistentSet
        //         这是 Hibernate内置的类型, 该类型具有延迟加载和存放代理对象的功能.
        //可能出现懒加载问题

        // 默认使用懒加载
//        Order order = session.get(Order.class, 1);
//        System.out.println(order.getName());
//        System.out.println(order.getCustomer().getClass().getName());

    }

    3. 测试删除数据(略)

    4. 测试更新数据(略)

    

    Customer.hbm.xml中的<set>标签还有很多属性可以选, 比如: order-by="": 值为数据列的某列列名.

Hibernate一对多(多对一)关联关系的更多相关文章

  1. Hibernate-ORM:12.Hibernate中的多对多关联关系

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的多对多关联关系的操作,准备的篇幅较少,望海涵 一,讲述多对多 多对多的关联 ...

  2. (转)Hibernate框架基础——多对多关联关系映射

    http://blog.csdn.net/yerenyuan_pku/article/details/52756536 多对多关联关系映射 多对多的实体关系模型也是很常见的,比如学生和课程的关系.一个 ...

  3. Hibernate 一对多自身双向关联关系 用于类别表的实现

    分类:一对多自身双向关联关系 Java持久化类: package com.hyy.hibernate.one_to_many.domain; import java.util.HashSet; imp ...

  4. Hibernate 一对多/多对多

    一对多关联(多对一): 一对多关联映射: 在多的一端添加一个外键指向一的一端,它维护的关系是一指向多 多对一关联映射: 咋多的一端加入一个外键指向一的一端,它维护的关系是多指向一 在配置文件中添加: ...

  5. Hibernate -- 一对多的双向关联关系

    示例代码: Customer.java package cn.itcast.many2onedouble; import java.util.HashSet; import java.util.Set ...

  6. hibernate一对多多对一双向

    注意事项:一对多,多对一双向关联,在一的一方的多的getSet集合上的oneToMany上加上mappedBy.告诉hibernate由多的方一来维护关系.这也符合逻辑 ,本来外键就是在加在多的一方. ...

  7. hibernate 一对多 多对一 关系表 增删改查大礼包ps二级查也有

    今天来到混元气功 这货大概的意思就是你中有我 我中有你 ps 这里就要说到维护关系 ps写这个用了我一下午.......也是刚刚好复习到这里 顺便就写写 注意:一般都在多方维护关系,至于是用单向还是用 ...

  8. Hibernate一对多自关联、多对多关联

    今天分享hibernate框架的两个关联关系    多对多关系注意事项 一定要定义一个主控方 多对多删除 主控方直接删除 被控方先通过主控方解除多对多关系,再删除被控方 禁用级联删除 关联关系编辑,不 ...

  9. Hibernate(6)—— 一对多 和 多对多关联关系映射(xml和注解)总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XM ...

随机推荐

  1. 68. 蓄水池抽样(Reservoir Sampling)

    [本文链接] http://www.cnblogs.com/hellogiser/p/reservoir-sampling.html 问题起源于编程珠玑Column 12中的题目10,其描述如下: H ...

  2. IAR for msp430 MDK中 warning: #223-D: function "xxx" declared implicitly 解决方法

    今天在EINT的范例里添加了一个函数,即eint.c中添加了一个datawrite()的函数,并在主函数main.c中调用,编译便警告 warning: #223-D: function " ...

  3. 论文笔记之:Deep Attention Recurrent Q-Network

    Deep Attention Recurrent Q-Network 5vision groups  摘要:本文将 DQN 引入了 Attention 机制,使得学习更具有方向性和指导性.(前段时间做 ...

  4. MFC CPtrLink的使用

    if (!m_SALink.IsEmpty()) { POSITION pos = m_SALink.GetHeadPosition(); for (int j = 0; j < m_SALin ...

  5. 淘宝ip库接口调用

    function ip($ip) {     $url="http://ip.taobao.com/service/getIpInfo.php?ip=".$ip;     $ipi ...

  6. MySQL管理_数据库启动与关闭

    MySQL数据库服务器通常指的的是mysqld,而命令行mysql则是mysql客户端程序,这两个概念通常容易混淆.通常启动mysql服务器即是启动mysqld进程,mysqld启动后,可以通过mys ...

  7. SQL Server DBA日常查询视图_数据库对象视图

    1.数据库 use master; exec sp_helpdb 1.1查询数据库大小 1.2查询数据库状态 use msdb select name, user_access_desc, --用户访 ...

  8. win7 :安装SQL2005

     转载:http://www.cnblogs.com/icewee/articles/2019783.html 操作系统:Microsoft Windows 7 旗舰版(64位) 数据库版本:SQL ...

  9. gulp.js简单操作

    一.安装gulp 1.深入设置任务之前,需先安装gulp: $ npm install gulp -g 2.这会将gulp安装到全域环境下,让你可以存取gulp的CLI.接著,需要在本地端的专案进行安 ...

  10. python学习-day15:函数作用域、匿名函数、函数式编程、map、filter、reduce函数、内置函数r

    ---恢复内容开始--- 一.全局变量与局部变量 在子程序中定义的变量称为局部变量, 在程序的一开始定义的变量称为全局变量. 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序.当全局变量与 ...