zoukankan      html  css  js  c++  java
  • Hibernate表关系03

    一. 一对多映射

    1.基本应用

    1.1 准备项目

    • 创建项目:hibernate-02-relation

    • 引入jar,同前一个项目

    • 复制实体(客户)、映射、配置、工具类

    1.2 创建订单表

    表名: t_order

    语句

    1 CREATE TABLE `t_order` (
    2   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
    3   `orderno` varchar(20) DEFAULT NULL COMMENT '订单编号',
    4   `product_name` varchar(100) DEFAULT NULL COMMENT '商品名称',
    5   `customer_id` bigint(20) DEFAULT NULL COMMENT '客户id',
    6   PRIMARY KEY (`id`),
    7   KEY `order_customer_fk` (`customer_id`),
    8   CONSTRAINT `order_customer_fk` FOREIGN KEY (`customer_id`) REFERENCES `t_customer` (`c_id`)
    9 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    View Code

    1.3 创建Order实体类

     1 /**
     2  * 订单(多方)
     3  */
     4 public class Order {
     5     private Long id;
     6     private String orderno;
     7     private String productName;
     8 
     9     //关联客户
    10     private Customer customer;
    11     
    12     //getter seter toString
    13 }
    View Code

    1.4 修改Customer实体类

    添加关联订单

     1 /**
     2  * 客户(一方)
     3  */
     4 public class Customer{
     5     private Long id;
     6     private String name;
     7     private Character gender;
     8     private Integer age;
     9     private String level;
    10     
    11     //关联订单
    12     private Set<Order> orders = new HashSet<Order>();
    13     //getter setter toString
    14 }
    View Code

    1.5 Customer配置一对多

       <class name="Customer" table="t_customer">
             ......
             <!-- 一对多配置 -->
             <set name="orders">
                 <!-- 外键字段名称 -->
                 <key column="customer_id"></key>
                 <one-to-many class="Order"/>
             </set>
         </class>
    View Code

    1.6 Order配置多对一

     1 <hibernate-mapping package="com.qfedu.hibernate.pojo.one2many">
     2  
     3      <class name="Order" table="t_order">
     4          <id name="id" column="id">
     5              <generator class="native"></generator>
     6          </id>
     7          <property name="orderno" column="orderno"></property>
     8          <property name="productName" column="product_name"></property>
     9          
    10          <!-- 多对一配置 
    11              name javaBean中的属性
    12              class 属性的全路径
    13              colunm 对应的列名
    14              -->
    15         -->
    16          <many-to-one name="customer" class="com.itqf.domain.Customer" column="customer_id" />
    17      </class>
    18 </hibernate-mapping> 
    View Code

    1.7 将映射文件加入hibernate.cfg.xml

    1 <mapping resource="/pojo/one2many/Customer.hbm.xml"/>
    2 <mapping resource="/pojo/one2many/Order.hbm.xml"/>
    View Code

    1.8 测试新增关联数据

     1 public class One2manyTest {
     2     /**
     3      * 需求:1个客户 2张订单
     4      */
     5     @Test
     6     public void testCreateOrder(){
     7         //准备数据
     8         Customer cust = new Customer();
     9         cust.setName("海伦");
    10         cust.setGender('女');
    11         cust.setAge(18);
    12         cust.setLevel("VIP");
    13       
    14         Order o1 = new Order();
    15         o1.setOrderno("201709070001");
    16         o1.setProductName("JavaWeb开发详解");
    17       
    18         Order o2 = new Order();
    19         o2.setOrderno("201709070002");
    20         o2.setProductName("Spring开发详解");
    21       
    22         Session session = HibernateUtil.openSession();
    23         Transaction tx = session.beginTransaction();
    24         
    25         //建立一对多双向关系
    26         cust.getOrders().add(o1);
    27         cust.getOrders().add(o2);
    28       
    29         o1.setCustomer(cust);
    30         o2.setCustomer(cust);
    31       
    32         session.save(cust);
    33         session.save(o1);
    34         session.save(o2);
    35       
    36         tx.commit();
    37         session.close();
    38     }
    39 }
    View Code

    1.9 测试查询订单

     1 /**
     2    * 查询操作
     3    */
     4  @Test
     5  public void testSearch(){   
     6      Session session = HibernateUtil.openSession();
     7      Transaction tx = session.beginTransaction();
     8         
     9      //查询一个客户,关联查询订单
    10      Customer cust = session.get(Customer.class, 3L);
    11      System.out.println(cust.getName()+"的订单:");
    12      Set<Order> orders = cust.getOrders();
    13      for (Order order : orders) {
    14          System.out.println(order.getOrderno()+","+order.getProductName());
    15      }
    16         
    17      tx.commit();
    18      session.close();
    19   }
    View Code
    2.cascade级联操作

    2.1. 测试级联保存

    当只保存双向关联关系的一方时,会报告错误,此时应该在customer中配置级联保存

    级联操作:就是操作一个对象的时候,想同时操作它的关联对象。

    修改映射文件

    <set name="orders" cascade="save-update">

    如下用例,可以先测试查看报错信息;再配置上面的级联保存,然后再次进行测试,成功。

     1   /**
     2      * 保存操作 - 级联保存
     3      */
     4     @Test
     5     public void testCascadeSave(){
     6         //准备数据
     7         Customer cust = new Customer();
     8         cust.setName("海伦");
     9         cust.setGender('女');
    10         cust.setAge(18);
    11         cust.setLevel("VIP");
    12         
    13         Order o1 = new Order();
    14         o1.setOrderno("201709070001");
    15         o1.setProductName("JavaWeb开发详解");
    16         
    17         Order o2 = new Order();
    18         o2.setOrderno("201709070002");
    19         o2.setProductName("Spring开发详解");
    20         
    21         Session session = HibernateUtil.openSession();
    22         Transaction tx = session.beginTransaction();
    23         
    24         //建立一对多单向关联
    25         cust.getOrders().add(o1);
    26         cust.getOrders().add(o2);
    27         //o1.setCustomer(cust);
    28         //o2.setCustomer(cust);
    29       
    30         session.save(cust);//使用级联保存 (  想保存客户的时候,同时保存订单 )
    31         //session.save(o1);//设置级联保存后不用保存订单
    32         //session.save(o2);
    33         
    34         tx.commit();
    35         session.close();
    36     }
    View Code

    2.2 测试级联删除

    当只删除父记录时,在删除客户的时候,Hibernate会把订单表的外键值置空,此时可以配置级联删除

    <set name="orders" cascade="save-update,delete">

    测试代码

     1    /**
     2      * 级联删除
     3      * 注意:
     4      *  1)如果没有级联删除,那么在删除客户的时候,会把订单表的cust_id外键值设置为null
     5      *  2)有了级联删除,那么在删除客户的时候,会同时把该客户的所有订单删除
     6      */
     7     @Test
     8     public void testCascadeDelete(){
     9         //准备数据
    10         
    11         Session session = HibernateUtil.openSession();
    12         Transaction tx = session.beginTransaction();
    13         
    14         Customer cust = session.get(Customer.class, 4L);
    15         session.delete(cust);
    16         
    17         tx.commit();
    18         session.close();
    19     }
    View Code

    3、inverse关系反转

    3.1、分析前面的测试

    1. 运行级联保存的测试用例

    2. 查看日志中的sql语句

    插入一个用户、两个订单,应该执行3个insert语句

    但是发现日志中多打印了两个update语句

    默认情况下inverse的值是false:

    <set name="orders" cascade="all" inverse="false">

    表示customer 一方需要维护关联关系,因此需要维护外键,有关联记录生成时,会做外键的更新操作。

    而这个更新操作是没有必要的,因为order插入的时候已经将外键值插入。

    所以customer中的update的语句是多余的

    3.2、优化

    inverse 配置:表示是否把关联关系的维护权反转(放弃)

    false:默认值,不反转(不放弃)

    true:反转(放弃)

    放弃customer方的外键维护

    <set name="orders" cascade="all" inverse="true">

    重新测试,发现只有三条insert语句

    3.3、也可以保存订单

    step1:保存时,保存订单

    1  //建立一对多单向关联
    2  //cust.getOrders().add(o1);
    3  //cust.getOrders().add(o2);
    4    o1.setCustomer(cust);
    5    o2.setCustomer(cust);
    6  //session.save(cust);//使用级联保存 (  想保存客户的时候,同时向保存订单 )
    7    session.save(o1);
    8    session.save(o2);
    View Code

    step2:在订单端设置级联保存

    <!-- 多对一配置 -->
    <many-to-one name="customer" class="Customer" column="customer_id" cascade="all"/>

    3.4、结论

    通常在一对多的关联配置中,多方无法放弃关系维护权,所以应该放弃 1 方的维护权,意味着在 1 方加上 inverse=true 配置

    二. 多对多映射

    需求: 用户与角色是多对多的关系

    1.基本配置

    1.1 创建User实体类

    1 public class User{
    2     
    3     private Integer id;
    4     private String name;
    5     
    6     //关联角色
    7     private Set<Role> roles = new HashSet<Role>();
    8 }
    View Code

    1.2 创建Role实体类

    1 public class Role{
    2     private Integer id;
    3     private String name;
    4     
    5     //关联用户
    6     private Set<User> users = new HashSet<User>();
    7 }
    View Code

    1.3 User映射配置

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     
     6 <hibernate-mapping package="com.qfedu.hibernate.pojo.many2many">
     7  
     8      <class name="User" table="t_user">
     9          <id name="id" column="id">
    10              <generator class="native"></generator>
    11          </id>
    12          <property name="name" column="name"></property>
    13          
    14          <!-- 多对多映射 -->
    15          <!-- 
    16              table:中间表名
    17           -->
    18          <set name="roles" table="t_user_role" >
    19              <!-- 当前方在中间表的外键 -->
    20              <key column="user_id"/>
    21              <!-- column:对方在中间表的外键 -->
    22              <many-to-many class="Role" column="role_id"/>
    23          </set>
    24      </class>
    25 </hibernate-mapping> 
    View Code

    1.4 Role配置

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5     
     6 <hibernate-mapping package="com.qfedu.hibernate.pojo.many2many">
     7  
     8      <class name="Role" table="t_role">
     9          <id name="id" column="id">
    10              <generator class="native"></generator>
    11          </id>
    12          <property name="name" column="name"></property>
    13          
    14          <!-- 多对多映射 -->
    15          <!-- 
    16              table:中间表名
    17           -->
    18          <set name="users" table="t_user_role" >
    19              <!-- 当前方在中间表的外键 -->
    20              <key column="role_id"/>
    21              <!-- column:对方在中间表的外键 -->
    22              <many-to-many class="User" column="user_id"/>
    23          </set>
    24      </class>
    25  
    26 </hibernate-mapping>  
    View Code

    1.5 核心配置文件添加映射路径

    1   <mapping resource="/pojo/many2many/User.hbm.xml"/>
    2   <mapping resource="/pojo/many2many/Role.hbm.xml"/>
    View Code

    1.6、测试增加

    注意:以下测试用例如果直接执行,会报告联合主键插入重复的错误。因此可以在任意一方设置inverse选项=true

    <set name="users" table="t_user_role" inverse="true">

    测试代码:

     1 public class Many2manyTest {
     2     /**
     3      * 需求:创建一个用户一个角色
     4      */
     5     @Test
     6     public void testCreateUser() {
     7         
     8         User u1 = new User();
     9         u1.setName("Helen1");
    10         
    11         Role r1 = new Role();
    12         r1.setName("超级管理员1");
    13         
    14         u1.getRoles().add(r1);
    15         r1.getUsers().add(u1);
    16         
    17         Session session = HibernateUtil.openSession();
    18         Transaction tx = session.beginTransaction();
    19         //双向都保存
    20         session.save(u1);
    21         session.save(r1);
    22         
    23         tx.commit();
    24         session.close();
    25     }
    26 }
    View Code

    4.7、级联保存

    注意:在多对多的保存中,如果不设置级联保存,也不设置inverse="true",那么会报告联合主键重复的错误。

    可以设置级联保存,在User的多对多关联中设置如下:

    <set name="roles" table="t_user_role" cascade="save-update">

    测试代码:

     1 public class Many2manyTest {
     2     /**
     3      * 需求:创建一个用户一个角色
     4      */
     5     @Test
     6     public void testCreateUser() {
     7         
     8         User u1 = new User();
     9         u1.setName("Helen1");
    10         
    11         Role r1 = new Role();
    12         r1.setName("超级管理员1");
    13         
    14         u1.getRoles().add(r1);
    15         //r1.getUsers().add(u1);
    16         
    17         Session session = HibernateUtil.openSession();
    18         Transaction tx = session.beginTransaction();
    19         
    20         session.save(u1);
    21         //session.save(r1);
    22         
    23         tx.commit();
    24         session.close();
    25     }
    26 }
    View Code

    4.8、级联删除

    当没有设置级联删除的时候,如果删除User表中的记录,那么只删除User表和关联表中的记录

    当设置了级联删除的时候,如果删除User表中的记录,那么会将User表、关联表和Role表中的记录全部删除!

    <set name="roles" table="t_user_role" cascade="save-update,delete">

    测试:

     1     @Test
     2     public void testCascadeDelete() {
     3         
     4         Session session = HibernateUtil.openSession();
     5         Transaction tx = session.beginTransaction();
     6         
     7         User u = session.get(User.class, 6);
     8         session.delete(u);
     9         
    10         tx.commit();
    11         session.close();
    12     }
    View Code

    三. 一对一映射的两种设计方案

    需求:公民表和身份证表是一对一的关系

    设计表的两种方案:

    1. 一对一唯一外键关联

    1.1 创建持久化类

    Person

    1 public class Person {
    2     private Integer id;
    3     private String name;
    4     
    5     //关联身份证
    6     private Card card;
    7 }
    View Code

    Card

    1 public class Card {
    2     private Integer id;
    3     private String cardno;
    4     
    5     //关联公民
    6     private Person person;
    7 }
    View Code

    1.2 配置映射文件

    Person.hbm.xml

    <hibernate-mapping package="pojo.one2one_fk">
     
         <class name="Person" table="t_person">
             <id name="id" column="id">
                 <generator class="native"></generator>
             </id>
             <property name="name" column="name"></property>
             
             <!-- 一对一映射 -->
             <one-to-one name="card" class="Card" />
         </class> 
     
    </hibernate-mapping>
    View Code

    Card.hbm.xml

     1 <hibernate-mapping package="pojo.one2one_fk">
     2  
     3      <class name="Card" table="t_card">
     4          <id name="id" column="id">
     5              <generator class="native"></generator>
     6          </id>
     7          <property name="cardno" column="cardno"></property>
     8          
     9          <!-- 唯一外键(一对一) -->
    10          <many-to-one name="person" class="Person" column="person_id" unique="true" />
    11      </class> 
    12  
    13 </hibernate-mapping> 
    View Code

    1.3 核心配置

    1    <mapping resource="/pojo/one2one_fk/Person.hbm.xml"/>
    2    <mapping resource="/pojo/one2one_fk/Card.hbm.xml"/>
    View Code

    1.4 测试

     1 public class One2OneTest {
     2     @Test
     3     public void testCreatePerson() {
     4         
     5         Session session = HibernateUtil.openSession();
     6         Transaction tx = session.beginTransaction();
     7         
     8         Person p = new Person();
     9         p.setName("Helen");
    10         
    11         Card c = new Card();
    12         c.setCardno("1234");
    13         
    14         p.setCard(c);
    15         c.setPerson(p);
    16         
    17         session.save(p);
    18         session.save(c);
    19         
    20         tx.commit();
    21         session.close();
    22     }
    23 }
    View Code

    2. 一对一主键关联

    2.1 创建持久化类

    Person

    1 public class Person {
    2     private Integer id;
    3     private String name;
    4     
    5     //关联身份证
    6     private Card card;
    7 }
    View Code

    Card

    1 public class Card {
    2     private Integer id;
    3     private String cardno;
    4     
    5     //关联公民
    6     private Person person;
    7 }
    View Code

    2.2 配置

    Person.hbm.xml

     1 <hibernate-mapping package="pojo.one2one_pk">
     2  
     3      <class name="Person" table="t_person_pk">
     4          <id name="id" column="id">
     5              <generator class="native"></generator>
     6          </id>
     7          <property name="name" column="name"></property>
     8          
     9          <!-- 主键(一对一映射) -->
    10          <one-to-one name="card" class="Card" />
    11      </class> 
    12  
    13 </hibernate-mapping> 
    View Code

    Card.hbm.xml

     1 <hibernate-mapping package="pojo.one2one_pk">
     2  
     3      <class name="Card" table="t_card_pk">
     4          <id name="id" column="id">
     5              <generator class="native"></generator>
     6          </id>
     7          <property name="cardno" column="cardno"></property>
     8          
     9          <!-- 关联主键(一对一) -->
    10          <!--constrained="true" 表示检查约束,查询时使用select查询,而不是join查询方式-->
    11          <one-to-one name="person" class="Person" constrained="true" />
    12          
    13      </class> 
    14  
    15 </hibernate-mapping> 
    View Code

    2.3 修改核心配置文件

    1   <mapping resource="/pojo/one2one_pk/Person.hbm.xml"/>
    2   <mapping resource="/pojo/one2one_pk/Card.hbm.xml"/>
    View Code

    2.4 测试

     1 public class One2OneTestPK {
     2     @Test
     3     public void testCreatePerson() {
     4         
     5         Session session = HibernateUtil.openSession();
     6         Transaction tx = session.beginTransaction();
     7         
     8         Person p = new Person();
     9         p.setName("Helen");
    10         
    11         Card c = new Card();
    12         c.setCardno("1234");
    13         
    14         p.setCard(c);
    15         c.setPerson(p);
    16         
    17         session.save(p);
    18         session.save(c);
    19         
    20         tx.commit();
    21         session.close();
    22     }
    23 }
    View Code
  • 相关阅读:
    紫书 例题8-6 UVa 1606(扫描法)
    紫书 例题8-5 UVa11054(等价转换)
    紫书 例题8-4 UVa 11134(问题分解 + 贪心)
    紫书 例题8-3 UVa 1152(中途相遇法)
    紫书 例题8-2 UVa 11605(构造法)
    Codeforces Round #437 (Div. 2, based on MemSQL Start[c]UP 3.0
    2016ACM/ICPC亚洲区沈阳站
    Tenka1 Programmer Contest D
    [Gym-101512C] 凸包+最远点对
    ZOJ
  • 原文地址:https://www.cnblogs.com/sueyyyy/p/9575789.html
Copyright © 2011-2022 走看看