一. 一对多映射
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 toString13 }
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 toString14 }
1.5 Customer配置一对多
??<class name="Customer" table="t_customer"> ????????...... ????????<!-- 一对多配置 --> ????????<set name="orders"> ????????????<!-- 外键字段名称 --> ????????????<key column="customer_id"></key> ????????????<one-to-many /> ????????</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 ></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" 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、分析前面的测试
运行级联保存的测试用例
查看日志中的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" 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 ></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 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 ></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 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 ></generator> ????????</id> ????????<property name="name" column="name"></property> ?????????????????<!-- 一对一映射 --> ????????<one-to-one name="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 ></generator> 6 ?????????</id> 7 ?????????<property name="cardno" column="cardno"></property> 8 ??????????9 ?????????<!-- 唯一外键(一对一) -->10 ?????????<many-to-one name="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 ></generator> 6 ?????????</id> 7 ?????????<property name="name" column="name"></property> 8 ??????????9 ?????????<!-- 主键(一对一映射) -->10 ?????????<one-to-one name="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 ></generator> 6 ?????????</id> 7 ?????????<property name="cardno" column="cardno"></property> 8 ??????????9 ?????????<!-- 关联主键(一对一) -->10 ?????????<!--constrained="true" 表示检查约束,查询时使用select查询,而不是join查询方式-->11 ?????????<one-to-one name="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 }
Hibernate表关系03
原文地址:https://www.cnblogs.com/sueyyyy/p/9575789.html