学习笔记之Hibernate_映射关系之一对多映射关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记之Hibernate_映射关系之一对多映射关系相关的知识,希望对你有一定的参考价值。

一、单向一对多映射关系

实体类的创建

1.本例子的 多的一方是Order,一的一方是Customer,一个Customer 可以有很多个Order, 而一个Order只能属于一个Customer。

    实体类Customer

package hibernates.entities.n21;

public class Customer {
    private Integer customerId;
    private String customerName;
    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 Customer(String customerName) {
        super();
        this.customerName = customerName;
    }
    public Customer() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Customer [customerId=" + customerId + ", customerName=" + customerName + "]";
    }
}

 

    实体类Order

package hibernates.entities.n21;

public class Order {
    private Integer orderId;
    private String orderName;
    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;
    }
    public Order(String orderName, Customer customer) {
        super();
        this.orderName = orderName;
        this.customer = customer;
    }
    public Order() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Order [orderId=" + orderId + ", orderName=" + orderName + ", customer=" + customer + "]";
    }
}

编写基础映射文件

Order.hbm.xml的编写:主要是编写<many-to-one>标签

 

<?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-11-27 21:13:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>

    <class name="hibernates.entities.n21.Order" table="ORDERS">
    
        <id name="orderId" type="java.lang.Integer">
            <column name="ORDERID" />
            <generator class="native" />
        </id>
        
        <property name="orderName" type="java.lang.String">
            <column name="ORDERNAME" />
        </property>
        
        <!-- 
            映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 
            name: 多这一端关联的一那一端的属性的名字
            class: 一那一端的属性对应的类名
            column: 一那一端在多的一端对应的数据表中的外键的名字
        -->
        <many-to-one name="customer" class="hibernates.entities.n21.Customer" >
            <column name="CUSTOMER_ID" />
        </many-to-one>
        
    </class>
    
</hibernate-mapping>

 

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-11-27 21:13:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>

    <class name="hibernates.entities.n21.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="CUSTOME_RNAME" />
        </property>
        
    </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://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
    
        <!-- 配置连接数据库的基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql:///hibernate</property>
        
        <!-- 配置 hibernate 的基本信息 -->
        <!-- hibernate 所使用的数据库方言 
        <property name="dialect">org.hibernate.dialect.MySQLMyISAMDialect</property>        
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>        
        <property name="dialect">org.hibernate.dialect.MySQLDialect</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>
        
        <!-- 指定关联的 .hbm.xml 文件 -->
        <mapping resource="hibernates/entities/n21/Customer.hbm.xml"/>
        <mapping resource="hibernates/entities/n21/Order.hbm.xml"/>
    
    </session-factory>
</hibernate-configuration>

 

对Order和Customer的增删改查的测试

package hibernates.entities.n21;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class HibernateTest {
        
    Session session;
    SessionFactory sessionFactory;
    Transaction transaction;
    
    @Before
    public void init() {
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }
    
    @After
    public void destroy() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }
    
    @Test
    public void testMany2OneSave() {
        Customer customer = new Customer();
        customer.setCustomerName("小明");
        Order order1 = new Order();
        order1.setOrderName("AA");
        Order order2 = new Order();
        order2.setOrderName("BB");
        
        //设定关联关系
        order1.setCustomer(customer);
        order2.setCustomer(customer);
        
        //执行  save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT
        //先插入 1 的一端, 再插入 n 的一端, 只有 INSERT 语句.
//        session.save(customer);
//        session.save(order1);
//        session.save(order2);
        
        //先插入 Order, 再插入 Customer. 3 条 INSERT, 2 条 UPDATE
        //先插入 n 的一端, 再插入 1 的一端, 会多出 UPDATE 语句!
        //因为在插入多的一端时, 无法确定 1 的一端的外键值. 所以只能等 1 的一端插入后, 再额外发送 UPDATE 语句.
        //推荐先插入 1 的一端, 后插入 n 的一端
        session.save(order1);
        session.save(order2);
        session.save(customer);
        
    }
    
    @Test
    public void testMany2OneGet() {
        //1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的
        //1 的那一端的对象!
        Order order = session.get(Order.class, 1);
        System.out.println(order);
        System.out.println(order.getCustomer().getClass().getName());
        
        session.close();
        
        //2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句. 
        Customer customer = order.getCustomer();
        System.out.println(customer);
        
        //3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时, 
        //若此时 session 已被关闭, 则默认情况下
        //会发生 LazyInitializationException 异常
        
        //4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象!
        
    }
    
    @Test
    public void testUpdate() {
        Order order = session.get(Order.class, 1);
        order.getCustomer().setCustomerName("555");
    }
    
    
    @Test
    public void testDelete() {
        //在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象
        Customer customer = session.get(Customer.class, 1);
        session.delete(customer);
    }
}

二、双向一对多映射关系

 实体类的创建(与一中的一样)

编写基础映射文件

Order.hbm.xml的编写:主要是编写<many-to-one>标签

 

<?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-12-1 19:54:01 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="hibernates.entities.n21.both.Order" table="BOTHORDERS">
        <id name="orderId" type="java.lang.Integer">
            <column name="ORDERID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDERNAME" />
        </property>
        <many-to-one name="customer" class="hibernates.entities.n21.both.Customer" fetch="join"
                cascade="delete">
            <column name="CUSTOMERID" />
        </many-to-one>
    </class>
</hibernate-mapping>

 

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-12-1 19:54:01 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="hibernates.entities.n21.both.Customer" table="BOTHCUSTOMERS">
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMERID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMERNAME" />
        </property>
        <set name="orders" table="BOTHORDERS" inverse="true" cascade="delete" order-by="CUSTOMERID DESC">
            <key>
                <column name="CUSTOMERID" />
            </key>
            <one-to-many class="hibernates.entities.n21.both.Order" />
</set> </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://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 配置连接数据库的基本信息 --> <property name="connection.username">root</property> <property name="connection.password">123456</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql:///hibernate</property> <!-- 配置 hibernate 的基本信息 --> <!-- hibernate 所使用的数据库方言 <property name="dialect">org.hibernate.dialect.MySQLMyISAMDialect</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> --> <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> <!-- 指定关联的 .hbm.xml 文件 --> <!-- <mapping resource="hibernates/entities/n21/Customer.hbm.xml"/> <mapping resource="hibernates/entities/n21/Order.hbm.xml"/>--> <mapping resource="hibernates/entities/n21/both/Order.hbm.xml"/> <mapping resource="hibernates/entities/n21/both/Customer.hbm.xml"/> </session-factory> </hibernate-configuration>

Set标签中的三个属性:inverse、 cascade、 order-by

inverse属性:在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系
在没有设置 inverse=true 的情况下,父子两边都维护父子关系,在一对多的关系中一般是把一的一端设置为true,这样可以让hibernate减少很多的update语句。

cascade属性:在对象 – 关系映射文件中, 用于映射持久化类之间关联关系的元素, <set>, <many-to-one> 和 <one-to-one> 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.
       all: 所有情况下均进行关联操作,即save-update和delete。
       none: 所有情况下均不进行关联操作。这是默认值。
       save-update: 在执行save/update/saveOrUpdate时进行关联操作。
       delete: 在执行delete 时进行关联操作。
       all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点

order-by属性:<set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序,order-by 属性中还可以加入 SQL 函数。
下面是对于这几个属性打的一些相关代码,以及一些发现:

 

package hibernates.entities.n21.both;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;



public class HibernateTest {
        
        
    Session session;
    SessionFactory sessionFactory;
    Transaction transaction;
    
    @Before
    public void init() {
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        Customer customer1 = new Customer();
        customer1.setCustomerName("AA");
        Customer customer2 = new Customer();
        customer2.setCustomerName("BB");
        Order order1 = new Order();
        Order order2 = new Order();
        customer1.getOrders().add(order1);
        customer1.getOrders().add(order2);
        customer2.getOrders().add(order1);
        customer2.getOrders().add(order2);
        order1.setCustomer(customer1);
        order2.setCustomer(customer1);
        order1.setCustomer(customer2);
        order2.setCustomer(customer2);
        session.save(customer1);
        session.save(customer2);
        session.save(order1);
        session.save(order2);
    }
    
    @After
    public void destroy() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }
    
    @Test
    public void testInverse() {
        //1.可以在 1 的一端的 set 节点指定 inverse=true, 来使 1 的一端放弃维护关联关系!
        //2.通过多的一端改变来改变表中的数据:
        Order order3 = session.get(Order.class, 1);
        order3.setOrderName("HH");
        order3.getCustomer().setCustomerName("BB");
        //3.通过一的一端来修改表中的数据:
        Customer customer3 = session.get(Customer.class, 1);
        customer3.setCustomerName("DD");
        customer3.getOrders().iterator().next().setCustomer(customer3);
        System.out.println(customer3.getOrders());
        
    }
    
    @Test
    public void testCascade() {
        //当<set> 中的 cascade的属性值为delete时一的一端的数据被删除时,它所关联的多的一端也被删除,<many-to-one>中的
        //cascade也具有同样的功能
        Customer customer3 = session.get(Customer.class, 1);
        session.delete(customer3);
        Order order3 = session.get(Order.class, 1);
        session.delete(order3);
    }
    
    @Test
    public void testOrderBy() {
        //下面两句输出语句都会使Hibernate查询customer关联的order表,然后按照order-by的设定排序查询
        Customer customer3 = session.get(Customer.class, 1);
        System.out.println(customer3.getOrders());
        System.out.println(customer3.getCustomerName());
    }
    
}

 











以上是关于学习笔记之Hibernate_映射关系之一对多映射关系的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate初探之一对多映射 继续学习

hibernate4之一对多关系映射

hibernate4之一对多关系映射

hibernate 表关系映射详解之一对多

hibernate入门三之关联映射(一对多和多对一)

hibernate的映射关系之一对多