Hibernate一对多的关联映射,详解(代码+图解)与应用 举个栗子,搞的清楚

本文详细介绍了如何在Hibernate中使用一对一和多对一关系创建数据库表、实体类及映射文件,包括配置级联操作,如保存、更新和删除的级联行为。通过实际测试类展示了级联操作的使用和注意事项。
摘要由CSDN通过智能技术生成

(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

<?xml version="1.0" encoding="UTF-8"?>

<class name=“com.itzheng.hibernate.domain.LinkMan”

table=“cst_linkman”>

一的一方的映射文件

Customer.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<class name=“com.itzheng.hibernate.domain.Customer”

table=“cst_customer”>

4、配置核心配置文件Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>

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

<mapping

resource=“com/itzheng/hibernate/domain/Customer.hbm.xml” />

<mapping

resource=“com/itzheng/hibernate/domain/LinkMan.hbm.xml” />

5、log4j.properties

direct log messages to stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.err

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

direct messages to file mylog.log

log4j.appender.file=org.apache.log4j.FileAppender

log4j.appender.file.File=c:mylog.log

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.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 trace

log4j.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();

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
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();

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-xZ7aC8LX-1714793144322)]

[外链图片转存中…(img-4YnyFNwE-1714793144322)]

[外链图片转存中…(img-xDWuKhXj-1714793144322)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值