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

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 }

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 }

1.5 Customer配置一对多

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

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> 

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

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

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 }

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   }

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     }

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     }

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);

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 }

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 }

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> 

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>  

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

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

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 }

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 }

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     }

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

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

设计表的两种方案:

1. 一对一唯一外键关联

1.1 创建持久化类

Person

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

Card

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

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>

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> 

1.3 核心配置

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

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 }

2. 一对一主键关联

2.1 创建持久化类

Person

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

Card

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

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> 

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> 

2.3 修改核心配置文件

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

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 }

原文地址:https://www.cnblogs.com/sueyyyy/p/9575789.html

时间: 2024-11-07 21:37:21

Hibernate表关系03的相关文章

六 Hibernate表关系及其配置

Hibernate的一对多关联映射 Hibernate的多对多关联映射 数据库表与表之间的关系:一对多,多对多,一对一 一对多:一个部门对应多个员工,一个员工只能属于一个部门.一个客户对应多个联系人,一个联系人只能属于一个客户 一对多建表:在多的一方创建外键. 多对多:一个学生可以选择多门课程,一门课程可以被多个学生选择.一个用户可以选择多个角色,一个角色可以被多个用户选择. 多对多建表:创建中间表.中间表至少有两个字段分别作为外键指向多对多双方的主键. 一对一(了解): 一般可以建成一张表.

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

一对多 传统模式:jdbc连接数据库的传统模式下,是通过主键连接外键实现一对多关系的映射, 其数据库中表的对应关系是在多方加入一方的主键,而后形成外键连接. Hibernate:引入hibernate框架后,通过类的形式来表示一对多的关系. 举例:订单与订单详细的关系,一个订单包含多个商品,多个商品属于一个订单,两者的关系是一对多的关系. 实现原理: 面向对象实现------ 在order类中加入item类的set集合 ,表示在订单类中包含有多个订单详细(集合表示). 层次结构: 步骤一:编写实

hibernate 表关系映射详解之继承关系

举例:亚马逊的网上商城可以卖很多东西,比如说图书,电器,水果等等,那么我们以面向对象的理念去抽象一个商品类,他具有商品的共有属性,比如说上架时间,当前         价格,优惠价格等待,商品可以继承商品类,也可以保有自己的属性,比如说商品名等等.这种关系称为继承. 上文说到继承,那么怎么在数据库中体现继承,以及在hibernate实现继承. 数据库表中体现继承,可以先创建一个商品类表,然后创建一个商品表(类型不定),他们之间拥有同样的主键建立联系. 表结构: 如何在hibernate中实现继承

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

举例:用户和邮箱的关系,一个用户拥有一个邮箱,一个邮箱属于一个用户 关系图: 实现原理:因为两者皆是一方,无论在那一方加入,都可实现单项映射. 配置文件: 结构图: 实体类: hibernate实现映射一对一中有两种方法. 方法一(通过多对一映射): 步骤一: 在Customer类中加入Email类 步骤二:配置customer类的映射文件  -- > Customer.hbm.xml 本来多对一的映射,加入unique(唯一)之后,就很巧妙的变成一对一的映射,网上说这样的拓展性很好,没试过,这

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

举例:商品类型表与商品表,每种类型对应多个商品,每个商品对应多种类型 关系图: hirbernate实现多对多映射有两种方法,第一种是通过中间表直接映射,第二种是通过中间表间接映射. 直接映射: 配置实体类(因为都是多对多的关系,所以双方都具有set集合): 配置实体类的映射文件: 分析:category类先通过category_Id与中间表tb_category_product建立联系,然后再通过多对多标签中的porduct_id与product类建立多对多联系. product类同上类似.

hibernate表关系

1.一对一 用户表可以查分成两个表,一个userInfo.一个userLogin表 实现方式: (1)使用外键:外键+唯一性约束+非空约束 (2)公用主键:公用主键,从表的主键同时也是外键,来源于主表的主键. 2. 一对多 使用外键,实现一对多关系,外键可以为null 主从关系:一:主表,多:从表  ,从表的外键必须是主表的主键或者null. 实现方法:Student     Clazz step1:在一个一方创建对象引用集合  Set<> private Set<Student>

Hibernate多表关系

Hibernate多表关系 hibernate 一对多(多对一) 创建实体 配置ORM映射文件 创建测试文件 双方关系维护 级联操作 外键的维护权管理 双方关系维护.级联操作.外键维护权之间的关系 一对多(多对一) 在一个视频管理的系统中应该包含这样两个表讲课人Speaker.视频Video.其中一个讲课人可以讲多个视频,而一个视频只能属于一个讲课人:在这里Speaker就是一的状态,Video就是多的状态. 创建实体 在Speaker中添加set集合(如果添加list集合需要在配置文件中额外配

Rhythmk 学习 Hibernate 05 - Hibernate 表间关系 [ManyToOne,OneToMany]

1.项目结构: 1.1.场景说明: 一个订单,包含多个产品 1.2.类文件: Order.java ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.rhythmk.model; import java.util.Date; public

Rhythmk 学习 Hibernate 05 - Hibernate 表间关系 [One To One]

1.One To One 单相 背景: 古代一个老婆  只能关联一个老公 husband.java ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.rhythmk.model; public class husband {          public Integer getHusbandId() {         return husbandId;     }     public void setHusba