Hibernate一对多的关联映射,详解(代码+图解)与应用 举个栗子,搞的清楚
发布日期:2021-06-29 15:01:39
浏览次数:2
分类:技术文章
本文共 13439 字,大约阅读时间需要 44 分钟。
Hibernate一对多的关联映射
一、数据库表与表之间的关系
1、一对多关系
(1)什么样的关系是属于一对多
一个部门可以对应多个员工,一个员工只能属于某一个部门 一个客户对应多个联系人,一个联系人只能属于某一个客户 游戏当中我们组队的时候,在组队的那段时间当中,一个队员只能属于一个队伍,但是一个队伍可以拥有多个队员 (2)一对多建表原则:2、多对多关系
(1)什么样的关系是属于多对多
一个学生可以选择多门课程,一门课程也可以被多个学生所选择。 一个用户可以选择多个角色,一个角色也可以被多个用户所选择。 (2)多对多键表原则3、一对一关系
(1)什么样的关系是属于一对一
一个公司只能有一个注册地址,一个注册地址只能被一个公司注册。 (2)一对一键表原则二、实际应用(创建表与类的关系)
1、创建项目引入架包
2、创建数据库和表
创建一对多数据库关系的表
(1)创建客户表CREATE TABLE `cst_customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)', `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源', `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业', `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话', `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话', PRIMARY KEY (`cust_id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
(2)创建联系人的表
CREATE TABLE `cst_linkman` ( `lkm_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', `lkm_name` VARCHAR(16) DEFAULT NULL COMMENT '联系人姓名', `lkm_cust_id` BIGINT(32) DEFAULT NULL COMMENT '客户id', `lkm_gender` CHAR(1) DEFAULT NULL COMMENT '联系人性别', `lkm_phone` VARCHAR(16) DEFAULT NULL COMMENT '联系人办公电话', `lkm_mobile` VARCHAR(16) DEFAULT NULL COMMENT '联系人手机', `lkm_email` VARCHAR(64) DEFAULT NULL COMMENT '联系人邮箱', `lkm_qq` VARCHAR(16) DEFAULT NULL COMMENT '联系人qq', `lkm_position` VARCHAR(16) DEFAULT NULL COMMENT '联系人职位', `lkm_memo` VARCHAR(512) DEFAULT NULL COMMENT '联系人备注', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;(3)创建实体 一的一方的实体,当中放置多的一方的集合 代码如下: 多的一方的实体,放置一的一方的对象 代码如下: 同时分别生成set和get方法
(4)创建映射文件
在项目文件夹下创建映射文件 多的一方的映射文件 LinkMan.hbm.xml一的一方的映射文件
Customer.hbm.xml4、配置核心配置文件Customer.hbm.xml
com.mysql.jdbc.Driver jdbc:mysql:///hibernate_day03 root root org.hibernate.dialect.MySQLDialect true true update org.hibernate.connection.C3P0ConnectionProvider 5 20 120 3000 4 thread
5、log4j.properties
### direct log messages to stdout ###log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.errlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d{ ABSOLUTE} %5p %c{ 1}:%L - %m%n### direct messages to file mylog.log ###log4j.appender.file=org.apache.log4j.FileAppenderlog4j.appender.file.File=c\:mylog.loglog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=%d{ ABSOLUTE} %5p %c{ 1}:%L - %m%n### set log levels - for more verbose logging change 'info' to 'debug' #### error warn info debug tracelog4j.rootLogger= info, stdout
6、配置工具类
package com.itzheng.hibernate.utils;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;/*Hibernate的工具类做hibernate的小练习,对configuration的configure()方法很好奇,为啥创建的对象还要执行这个方法呢。Configuration cfg = new Configuration().configure();原来configure()方法默认会在classpath下面寻找hibernate.cfg.xml文件,如果没有找到该文件,系统会打印如下信息并抛出HibernateException异常。其实不使用configure()方法也可以Configuration cfg = new Configuration();这时hibernate会在classpath下面寻找hibernate.properties文件,如果没有找到该文件,系统会打印如下信息并抛出HibernateException异常。 */public class HibernateUtils { public static final Configuration cfg; public static final SessionFactory sf; static { cfg = new Configuration().configure();// 获取与数据库的链接的配置文件 sf = cfg.buildSessionFactory();//开启事务建立与数据库之间的链接 } public static Session openSession() { return sf.openSession(); } public static Session getCurrentSession() { return sf.getCurrentSession(); }}
三、实际应用
1、编写测试类(一对多的基本配置和操作)
package com.itzheng.hibernate.demo1;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.Test;import com.itzheng.hibernate.domain.Customer;import com.itzheng.hibernate.domain.LinkMan;import com.itzheng.hibernate.utils.HibernateUtils;/* * 一对多的测试类 */public class HibernateDemo1 { @Test // 保存两个客户和三个联系人 并且建立好关系 public void demo01() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 创建两个客户 Customer customer1 = new Customer(); customer1.setCust_name("王东"); Customer customer2 = new Customer(); customer2.setCust_name("赵洪"); // 创建3个联系人 LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("分解"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("如花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("旺财"); // 设置关系 linkMan1.setCustomer(customer1);// 将客户放入到联系人当中 linkMan2.setCustomer(customer1); linkMan3.setCustomer(customer2); customer1.getLinkMans().add(linkMan1);// 将联系人放入到客户的集合当中 customer1.getLinkMans().add(linkMan2); customer2.getLinkMans().add(linkMan3); // 保存数据 session.save(linkMan1); session.save(linkMan2); session.save(linkMan3); session.save(customer1); session.save(customer2); transaction.commit(); }}
2、Hibernate的一对多相关的操作
(1)一对多的关系只保存一遍是否可以:
更改核心配置文件 测试代码@Test // 一对多关系只保存一边 是否可以 public void demo2() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("赵洪"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("如花"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); //只保存一边是否可以,不可以。 session.save(customer);//只保存客户 transaction.commit(); }
当只保存客户时:报错:瞬时对象异常:持久态对象关联了瞬时太的对象
customer —>save之后变成持久的了 但是LinkMan 还是瞬时的 当只保存联系人的时候:报错 解决办法通过级联的方式,保证只操控一个对象的时候就可以,同时操作其关联的对象 (2)一对多的级联操作:什么吗叫做级联
级联指的是,我们在操作一个对象的时候,会同时操作其关联的对象。 级联是有方向性的 a、操作一的一方的时候,会操作到多的一方。 b、操作多的一方的时候,会操作到一的一方。3、级联保存或者更新
(1)保存客户级联联系人(一的一方配置级联)
级联保存或更新的操作 保存客户级联联系人 操作的主体对象是客户对象,需要在客户的映射文件Customer.hbm.xml中 进行配置 cascade配置级联@Test // 级联保存或更新的操作 //保存客户级联联系人 //操作的主体对象是客户对象,需要在客户的映射文件Customer.hbm.xml中 进行配置 public void demo3() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("赵洪"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("如花"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); //只保存一边是否可以,需要级联联系人,保证操作客户就可以同时操作联系人 session.save(customer);//只保存客户 transaction.commit(); }
(2)保存联系人级联客户(多的一方配置级联)
级联保存或更新的操作 保存联系人级联客户 操作的主体对象是客户对象,需要在客户的映射文件LinkMan.hbm.xml中 进行配置@Test // 级联保存或更新的操作 // 保存联系人级联客户 // 操作的主体对象是客户对象,需要在客户的映射文件LinkMan.hbm.xml中 进行配置 public void demo4() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("铁蛋"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("小花"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); // 只保存一边是否可以,需要级联联系人,保证操作客户就可以同时操作联系人 session.save(linkMan);// 只保联系人 transaction.commit(); }
(3)测试对象的导航
测试对象的导航 前提:一对多的双方都设置了cascade=“save-update”@Test// 测试对象的导航// 前提:一对多的双方都设置了cascade="save-update"public void demo5() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("铁蛋"); LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("小花"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("大花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("二花"); linkMan1.setCustomer(customer);// 1号连续人关联客户 customer.getLinkMans().add(linkMan2);// 客户关联二号联系人 customer.getLinkMans().add(linkMan3);// 客户关联三号联系人 // 双方都设置了cascade session.save(linkMan1);// 发送4条insert语句,当保存一号联系人的时候,同时会将客户,二号联系人和三号联系都保存进去 transaction.commit();}
发送4条insert语句,当保存一号联系人的时候,同时会将客户,二号联系人和三号联系都保存进去
如果存储的是customer对象 发送3条insert语句 存储 客户 联系人2 联系人3 如果存储的是linkMan2对象 发送一条insert语句4、级联删除
1、级联删除:
删除一边的时候,同时会删除另一方的数据也一并删除。 2、删除客户级联删除联系人 (1)先往数据库当中保存数据@Test // 保存两个客户和三个联系人 并且建立好关系 public void demo01() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 创建两个客户 Customer customer1 = new Customer(); customer1.setCust_name("王东"); Customer customer2 = new Customer(); customer2.setCust_name("赵洪"); // 创建3个联系人 LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("分解"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("如花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("旺财"); // 设置关系 linkMan1.setCustomer(customer1);// 将客户放入到联系人当中 linkMan2.setCustomer(customer1); linkMan3.setCustomer(customer2); customer1.getLinkMans().add(linkMan1);// 将联系人放入到客户的集合当中 customer1.getLinkMans().add(linkMan2); customer2.getLinkMans().add(linkMan3); // 保存数据 session.save(linkMan1); session.save(linkMan2); session.save(linkMan3); session.save(customer1); session.save(customer2); transaction.commit(); }
在数据库当中直接删除客户是无法删除的,因为如果要删除客户首先要删除对应的联系人,之后才能删除客户(因为在创建联系人的时候设置了外键)
3、默认情况下删除@Test //级联删除: //删除客户级联删除联系人 public void demo6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //没有设置级联删除:默认情况 Customer customer = session.get(Customer.class,1l);//要想删除线查询对应的内容 session.delete(customer); transaction.commit(); }
默认情况下删除客户会先将联系人表当中的外键置空,然后删除客户对应表当中的数据
4、自定义情况下级联删除删除客户同时删除联系人 级联删除: 删除客户级联删除联系人,删除的主体是客户,需要在客户的映射文件当中Customer.hbm.xml配置 update保存或者更新 delete级联删除@Test // 级联删除: // 删除客户级联删除联系人,删除的主体是客户,需要在客户的映射文件当中Customer.hbm.xml配置 // public void demo6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 没有设置级联删除:默认情况 // Customer customer = session.get(Customer.class,1l);//要想删除线查询对应的内容 // session.delete(customer); Customer customer = session.get(Customer.class, 1l);// 要想删除线查询对应的内容 session.delete(customer); transaction.commit(); }5、删除联系人的时候同时级联删除客户(基本不用) 级联删除: 删除联系人级联删除客户,删除的主体是联系人,需要在联系人的映射文件当中LinkMan.hbm.xml配置
@Test // 级联删除: // 删除联系人级联删除客户,删除的主体是联系人,需要在联系人的映射文件当中LinkMan.hbm.xml配置 public void demo7() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //删除联系人的同时删除客户 LinkMan linkMan = session.get(LinkMan.class, 3l);//查询对应id的联系人对象 session.delete(linkMan); transaction.commit(); }
5、在一对多当中设置了双向的关联,产生一些多余的SQL语句
(1)举个栗子
运行demo1,创建两个客户@Test // 保存两个客户和三个联系人 并且建立好关系 public void demo01() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 创建两个客户 Customer customer1 = new Customer(); customer1.setCust_name("王东"); Customer customer2 = new Customer(); customer2.setCust_name("赵洪"); // 创建3个联系人 LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("分解"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("如花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("旺财"); // 设置关系 linkMan1.setCustomer(customer1);// 将客户放入到联系人当中 linkMan2.setCustomer(customer1); linkMan3.setCustomer(customer2); customer1.getLinkMans().add(linkMan1);// 将联系人放入到客户的集合当中 customer1.getLinkMans().add(linkMan2); customer2.getLinkMans().add(linkMan3); // 保存数据 session.save(linkMan1); session.save(linkMan2); session.save(linkMan3); session.save(customer1); session.save(customer2); transaction.commit(); }
public void demo8() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 查询二号联系人 LinkMan linkMan = session.get(LinkMan.class, 2l); // 查询2号客户 Customer customer = session.get(Customer.class, 2l); // 双向的关联 // 将查询到的客户设置到2号联系人当中 linkMan.setCustomer(customer);// 直接将对象放入到linkMan当中 // 将新设置的2号联系人放入到2号客户当中 customer.getLinkMans().add(linkMan);// 获取到linkMan集合将对象添加进去 transaction.commit(); }
重复修改lkm_cust_id
更改Linkman和Customer都活修改外键 产生多余的SQL语句 (2)解决产生多余SQL语句 a、单向维护: b、使其一方放弃外键维护权 使一的一方放弃外键维护权,多的一方维护和一的关系 在Customer.hbm.xml上 设置inverse=“true” 默认情况是false,设置为true为放弃外键使用权 再次执行上述demo8,只发送一次update语句,修改一次外键,而且是多的一方在变换时修改的外键 c、在一对多关联查询修改的时候。6、区分cascade和inverse
核心配置文件hibernate.cfg.xml
LinkMan.hbm.xml当中 Customer.hbm.xml 测试类@Test // 区分cascade和inverse的区别 public void demo9() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("李冰"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("分解"); customer.getLinkMans().add(linkMan);//获取到list集合将对象放入到集合当中 //条件是在Customer.hbm.xml的set当中配置了cascade="save-update" inverse="true" session.save(customer);//客户会插入到数据库,联系人也会插入到数据库,但是外键为null,因为cascade没有控制外键的权利 transaction.commit(); }
客户会插入到数据库,联系人也会插入到数据库,但是外键为null,因为cascade没有控制外键的权利
转载地址:https://code100.blog.csdn.net/article/details/105799609 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2024年04月27日 11时48分41秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
打破定式,突破屏障,走出自己的创意舒适区
2019-04-29
又一个程序员倒下-程序员防猝死指南
2019-04-29
如何搭建高可用redis架构?
2019-04-29
如何设计出优秀的Restful API?
2019-04-29
立足GitHub学编程:13个不容错过的Java项目
2019-04-29
容器管理大战:Kubernetes vs.Docker Swarm与Amazon ECS
2019-04-29
Java应用程序中的性能改进:ORM / JPA
2019-04-29
Kafka主题体系架构-复制、故障转移和并行处理
2019-04-29
怎么进行负载测试?
2019-04-29
很全!浅谈几种常用负载均衡架构
2019-04-29
java 性能调优:35 个小细节,让你提升 java 代码的运行效率
2019-04-29
HR面对89年的小伙说:简历看着是挺不错的,就是年纪有点大!
2019-04-29
MapReduce设计模式
2019-04-29
软件开发人员维护代码指南
2019-04-29
2019年一线大厂20个长问mongo面试题和答案
2019-04-29
你写的代码好像一条虫啊!
2019-04-29
这54个docker命令!你必须懂!
2019-04-29
2019阿里巴巴面试题+答案
2019-04-29
30张地图看懂世界格局,用大数据说话
2019-04-29