Hibernate表关系映射之一对多映射

亦凉 2022-09-28 05:59 299阅读 0赞

一、基本概述
在表中的一对多,是使用外键关联,通过一张表的一个键另一个表的外键来建立一多关系;而在类中表示为一个类中有一个集合属性包含对方类的很多对象,而在另一个类中,只包含前述类的一个对象,从而实现一对多关系的建立!
而在Hibernate中采用的是Set类型集合,使用来实现。
对于一对多的映射关系可以分为两种情况:单向映射和双向映射。
单向映射:只能从一方访问到另一方,无法反向访问。
双向映射:双方都可以通过映射访问到对方。
这里以双向映射为例,单向映射只需在一端的配置文件和代码中删除相应的代码块即可。
二、实例演示(双向映射)
1、模型抽象
这里以 Customer 和 Order 为例: 一个客户能发出多个订单, 而一个订单只能属于一个客户. 从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联。

Customer.java

  1. package com.chen.one2many;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. public class Customer {
  5. private Integer customerID;
  6. private String customerName;
  7. //持有一个order的集合对象,表示一个客户customer可以有多个订单order
  8. Set<Order> orders=new HashSet<>();
  9. public Integer getCustomerID() {
  10. return customerID;
  11. }
  12. public void setCustomerID(Integer customerID) {
  13. this.customerID = customerID;
  14. }
  15. public String getCustomerName() {
  16. return customerName;
  17. }
  18. public void setCustomerName(String customerName) {
  19. this.customerName = customerName;
  20. }
  21. public Set<Order> getOrders() {
  22. return orders;
  23. }
  24. public void setOrders(Set<Order> orders) {
  25. this.orders = orders;
  26. }
  27. }

Order.java

  1. package com.chen.one2many;
  2. public class Order {
  3. private Integer orderID;
  4. private String orderName;
  5. //持有一个Customer的引用,一个订单order只能属于一个用户customer
  6. private Customer customer;
  7. public Integer getOrderID() {
  8. return orderID;
  9. }
  10. public void setOrderID(Integer orderID) {
  11. this.orderID = orderID;
  12. }
  13. public String getOrderName() {
  14. return orderName;
  15. }
  16. public void setOrderName(String orderName) {
  17. this.orderName = orderName;
  18. }
  19. public Customer getCustomer() {
  20. return customer;
  21. }
  22. public void setCustomer(Customer customer) {
  23. this.customer = customer;
  24. }
  25. }

2、配置相关xml文件

Customer.hbm.xml

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

Order.hbm.xml

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

Hibernate.cfg.xml

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

3、编写测试方法

HibernateTest.java

  1. package com.chen.one2many;
  2. import java.util.Iterator;
  3. import java.util.Set;
  4. import org.hibernate.Session;
  5. import org.hibernate.SessionFactory;
  6. import org.hibernate.Transaction;
  7. import org.hibernate.cfg.Configuration;
  8. import org.hibernate.service.ServiceRegistry;
  9. import org.hibernate.service.ServiceRegistryBuilder;
  10. public class HibernateTest {
  11. private static SessionFactory sessionFactory;
  12. private static Session session;
  13. private static Transaction transaction;
  14. //定义事务初始化函数
  15. public static void init(){
  16. Configuration configuration = new Configuration().configure();
  17. ServiceRegistry serviceRegistry =
  18. new ServiceRegistryBuilder().applySettings(configuration.getProperties())
  19. .buildServiceRegistry();
  20. sessionFactory = configuration.buildSessionFactory(serviceRegistry);
  21. session = sessionFactory.openSession();
  22. transaction = session.beginTransaction();
  23. }
  24. //定义事务结束时的处理函数
  25. public static void doit(){
  26. transaction.commit();
  27. session.close();
  28. sessionFactory.close();
  29. }
  30. //编写自己的处理过程
  31. public static void test(){
  32. //初始化基本信息:一个客户chen有两个订单book和food
  33. Customer customer=new Customer();
  34. customer.setCustomerName("chen");
  35. Order order1=new Order();
  36. order1.setOrderName("book");
  37. Order order2=new Order();
  38. order2.setOrderName("food");
  39. //设置对应关系(双向映射)
  40. //关联customer
  41. order1.setCustomer(customer);
  42. order2.setCustomer(customer);
  43. //关联order
  44. customer.getOrders().add(order1);
  45. customer.getOrders().add(order2);
  46. //因为配置文件中cascade="save-update",所以保存customer时会级联保存与之相关的order
  47. session.save(customer);
  48. //从order表中获取customer
  49. Order orderResult=(Order) session.get(Order.class, 1);
  50. String ordername=orderResult.getOrderName();
  51. String customername=orderResult.getCustomer().getCustomerName();
  52. System.out.println(ordername+" is owned by "+customername);
  53. //从customer表中获取order
  54. Customer customerResult=(Customer) session.get(Customer.class, 1);
  55. Set<Order> set=customerResult.getOrders();
  56. System.out.println(set.size());
  57. for (Iterator iterator2 = set.iterator(); iterator2.hasNext();) {
  58. Order order = (Order) iterator2.next();
  59. System.out.println(order.getOrderName());
  60. }
  61. }
  62. public static void main(String[] args) {
  63. HibernateTest.init();
  64. HibernateTest.test();
  65. HibernateTest.doit();
  66. System.out.println("完成---------");
  67. }
  68. }

4、运行结果

数据表

customers

20170310134519592

orders

20170310134532295

运行窗口显示

20170310134544469

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

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 语句,且插入数据时无法同时插入外键列,因而无法为外键列添加非空约束。

发表评论

表情:
评论列表 (有 0 条评论,299人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Hibernate关系映射之一映射

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