表关系概述:

1、一 对应 一

一对夫妻,一个男人只能有一个老婆,一个女人只能有一个老公,即这种对应关系

2、一 对应 多 【多对一】

一个年级具有多个班级,一个班级具有对应的所属年级,即这种上下层级关系或者其他类似的

3、多 对应 多

授课老师和所授课程 一个授课老师可以教授多门课程,一个课程也可以被多个老师教授。即多重关系

数据库表设计的实现:

一对一只需要一个关联键即可

一对多,需要建立主表(一)从表(多)关系,从表设置外键来检索主表信息

多对多,对应的关系无法用外键实现,所以需要建立关联表,用来存储关联关系映射

实体类设计的实现:

一对一,对象附属,作为属性存在【包含】

一对多,对象仅表示一个记录,所以更改为一个对象的集合容器作为属性存在,或者使用继承实现

多对多

测试环境搭建:

customer.sql

/*创建客户表*/
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_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8; /*创建联系人表*/
CREATE TABLE cst_linkman (
lkm_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
lkm_name varchar(16) DEFAULT NULL COMMENT '联系人姓名',
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_position varchar(16) DEFAULT NULL COMMENT '联系人职位',
lkm_memo varchar(512) DEFAULT NULL COMMENT '联系人备注',
lkm_cust_id bigint(32) NOT NULL COMMENT '客户id(外键)',
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=3 DEFAULT CHARSET=utf8;

客户:

package cn.echo42.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set; /**
* @author DaiZhiZhou
* @file Spring-Data-JPA
* @create 2020-08-01 9:48
*/ @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity//表示当前类是一个实体类
@Table(name="cst_customer")//建立当前实体类和表之间的对应关系
public class Customer implements Serializable { @Id//表明当前私有属性是主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//指定主键的生成策略
@Column(name = "cust_id")//指定和数据库表中的cust_id列对应
private Long custId;
@Column(name = "cust_name")//指定和数据库表中的cust_name列对应
private String custName;
@Column(name = "cust_source")//指定和数据库表中的cust_source列对应
private String custSource;
@Column(name = "cust_industry")//指定和数据库表中的cust_industry列对应
private String custIndustry;
@Column(name = "cust_level")//指定和数据库表中的cust_level列对应
private String custLevel;
@Column(name = "cust_address")//指定和数据库表中的cust_address列对应
private String custAddress;
@Column(name = "cust_phone")//指定和数据库表中的cust_phone列对应
private String custPhone; //配置客户和联系人的一对多关系
@OneToMany(targetEntity = LinkMan.class)
@JoinColumn(name = "lkm_cust_id", referencedColumnName = "cust_id")
private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
}

联系人:

package cn.echo42.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; import javax.persistence.*;
import java.io.Serializable; /**
* @author DaiZhiZhou
* @file Spring-Data-JPA
* @create 2020-08-01 9:49
*/ @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name="cst_linkman")
public class LinkMan implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="lkm_id")
private Long lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
@Column(name="lkm_mobile")
private String lkmMobile;
@Column(name="lkm_email")
private String lkmEmail;
@Column(name="lkm_position")
private String lkmPosition;
@Column(name="lkm_memo")
private String lkmMemo; //多对一关系映射:多个联系人对应客户
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
private Customer customer;//用它的主键,对应联系人表中的外键
}

编写对应的Dao接口:

package cn.echo42.repository;

import cn.echo42.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /**
* @author DaiZhiZhou
* @file Spring-Data-JPA
* @create 2020-08-01 9:54
*/
public interface CustomerRepository extends JpaRepository<Customer, Integer> , JpaSpecificationExecutor<Customer> {
}
---------------------------------------------------------------------------------------------------------------------------
package cn.echo42.repository; import cn.echo42.domain.LinkMan;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /**
* @author DaiZhiZhou
* @file Spring-Data-JPA
* @create 2020-08-01 9:54
*/
public interface LinkManRepository extends JpaRepository<LinkMan, Integer>, JpaSpecificationExecutor<LinkMan> {
}

注解配置Jpa的配置信息

自动创建数据库表设置:create每次执行创建数据库表,update没有表才会创建

多表关系插入:

创建测试类:

import cn.echo42.config.ApplicationConfiguration;
import cn.echo42.domain.Customer;
import cn.echo42.domain.LinkMan;
import cn.echo42.repository.CustomerRepository;
import cn.echo42.repository.LinkManRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional; /**
* @author DaiZhiZhou
* @file Spring-Data-JPA
* @create 2020-08-01 10:06
*/ @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
public class MTRQ_Test { @Autowired
CustomerRepository customerRepository;
@Autowired
LinkManRepository linkManRepository; @Test
@Transactional
@Rollback(false) // 设置不自动回滚
public void addExecute(){
// 创建一个客户 & 联系人
Customer customer = new Customer();
customer.setCustName("百度"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李"); customerRepository.save(customer);
linkManRepository.save(linkMan);
} }

显示结果:

[org.hibernate.SQL]-alter table cst_linkman drop foreign key FKh9yp1nql5227xxcopuxqx2e7q
[org.hibernate.SQL]-drop table if exists cst_customer
[org.hibernate.SQL]-drop table if exists cst_linkman
[org.hibernate.SQL]-drop table if exists sys_user
[org.hibernate.SQL]-create table cst_customer (cust_id bigint not null auto_increment, cust_address varchar(255), cust_industry varchar(255), cust_level varchar(255), cust_name varchar(255), cust_phone varchar(255), cust_source varchar(255), primary key (cust_id))
[org.hibernate.SQL]-create table cst_linkman (lkm_id bigint not null auto_increment, lkm_email varchar(255), lkm_gender varchar(255), lkm_memo varchar(255), lkm_mobile varchar(255), lkm_name varchar(255), lkm_phone varchar(255), lkm_position varchar(255), lkm_cust_id bigint, primary key (lkm_id))
[org.hibernate.SQL]-create table sys_user (user_id integer not null auto_increment, user_is_del integer, user_name varchar(255), user_password varchar(255), user_status integer, primary key (user_id))
[org.hibernate.SQL]-alter table cst_linkman add constraint FKh9yp1nql5227xxcopuxqx2e7q foreign key (lkm_cust_id) references cst_customer (cust_id)

数据库查看:

可以看到联系人的外键这里没有百度,两个记录不具备任何联系,是相互独立的存在

要建立关系,我们则需要在联系人的集合中增加对象,表现出我们的关联关系:

    @Test
@Transactional
@Rollback(false) // 设置不自动回滚
public void addExecute(){
// 创建一个客户 & 联系人
Customer customer = new Customer();
customer.setCustName("百度"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李"); // 配置多表关系
customer.getLinkmans().add(linkMan); customerRepository.save(customer);
linkManRepository.save(linkMan);
}

再次执行的结果:

可以看到已经成功绑定到了

从客户表的角度上观察:

发送了两条插入语句,

一条插入记录

一条更新外键

我们配置了客户到联系人的关系,客户可以对外键进行维护

我们也可以换过来,从联系人的角度上关联客户:

    @Test
@Transactional
@Rollback(false) // 设置不自动回滚
public void addExecute2(){
// 创建一个客户 & 联系人
Customer customer = new Customer();
customer.setCustName("百度"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李"); // 在联系人的属性中设置客户,以关联
linkMan.setCustomer(customer); customerRepository.save(customer);
linkManRepository.save(linkMan);
}

结果一样

但是如果同时绑定设置就会出错了:

    @Test
@Transactional
@Rollback(false) // 设置不自动回滚
public void addExecute3(){
// 创建一个客户 & 联系人
Customer customer = new Customer();
customer.setCustName("百度"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李"); linkMan.setCustomer(customer);
customer.getLinkmans().add(linkMan);
customerRepository.save(customer);
linkManRepository.save(linkMan);
}

双方彼此的对象在不断相互引用:

解决方案是任意的一方放弃主键的维护即可:

原先联系人类的维护关系:

如果放弃,就需要这样设置:

But it not work .... 不晓得为什么,难道又有新的策略了?

【发现是使用了Lombok原因,这里也只要记住一点,放弃主键维护注意下Lombok辅助的问题】

级联操作:

ALL 所有操作

MERGE 更新
PERSIST 持久化 -> 保存
REMOVE 移除

取消之前设置的创建数据库表:

测试级联删除:

    @Test
@Transactional
@Rollback(false) // 设置不自动回滚
public void addExecute4(){
Specification<Customer> customerSpecification = (Specification<Customer>) (root, criteriaQuery, criteriaBuilder) -> {
// 获取比较的属性
Path<Object> cust_id = root.get("custId");
// 模糊要求指定参数类型
return criteriaBuilder.equal(cust_id, 1);
};
Optional<Customer> customerOptional = customerRepository.findOne(customerSpecification); Customer customer = customerOptional.get(); customerRepository.delete(customer);
}

【Spring Data JPA】08 多表关系 Part1 一对多关系操作的更多相关文章

  1. Spring Data JPA 实现多表关联查询

    本文地址:https://liuyanzhao.com/6978.html 最近抽出时间来做博客,数据库操作使用的是 JPA,相对比 Mybatis 而言,JPA 单表操作非常方便,增删改查都已经写好 ...

  2. spring data jpa关联查询(一对一、一对多、多对多)

    在实际过往的项目中,常用的查询操作有:1.单表查询,2.一对一查询(主表和详情表)3.一对多查询(一张主表,多张子表)4.多对多查询(如权限控制,用户.角色多对多).做个总结,所以废话不多说. 使用i ...

  3. spring data jpa之Auditing 表的创建时间,更新时间自动生成策略

    java实际编程中,几乎每一张表都会有createTime和updateTime字段,spring的优秀之处在于只要用几个注解,就帮我们解决该类问题,具体实现: 1,实体类添加注解: @EntityL ...

  4. Spring Boot:整合Spring Data JPA

    综合概述 JPA是Java Persistence API的简称,是一套Sun官方提出的Java持久化规范.其设计目标主要是为了简化现有的持久化开发工作和整合ORM技术,它为Java开发人员提供了一种 ...

  5. 集成Spring Data JPA

    1.Spring Data JPA简介 Spring Data是一个用于简化数据访问,并支持云服务的开源框 使用完成Spring Data JPA对user表的CRUD操作. 2.步骤 1.创建工程勾 ...

  6. JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文带你厘清个中曲直,给你个选择SpringDataJPA的理由!

    序言 Spring Data JPA作为Spring Data中对于关系型数据库支持的一种框架技术,属于ORM的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度. 本文档隶属于< ...

  7. Spring Boot 入门系列(二十七)使用Spring Data JPA 自定义查询如此简单,完全不需要写SQL!

    前面讲了Spring Boot 整合Spring Boot JPA,实现JPA 的增.删.改.查的功能.JPA使用非常简单,只需继承JpaRepository ,无需任何数据访问层和sql语句即可实现 ...

  8. 最近项目中使用Spring data jpa 踩过的坑

    最近在做一个有关OA项目中使用spring data JPA 操作数据库,结果遇到了补个不可思议的麻烦.困惑了好久. 首先看一下问题吧,这就是当时测试“设置角色时,需要首先删除该用户已经拥有的角色时” ...

  9. spring data jpa hibernate jpa 三者之间的关系

    JPA规范与ORM框架之间的关系是怎样的呢? JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服 ...

  10. Spring Data JPA 多个实体类表联合视图查询

    Spring Data JPA 查询数据库时,如果两个表有关联,那么就设个外键,在查询的时候用Specification创建Join 查询便可.但是只支持左连接,不支持右连接,虽说左右连接反过来就能实 ...

随机推荐

  1. react兄弟之间通信

    写入组件 import React, { Component } from 'react'//下面二个就是兄弟关系的组件 import Cmp1 from '../Child/Cmp1' import ...

  2. NFS练习

    NFS练习题 1.开放/nfs/share目录,提供给 任意用户 只读(/etc/exports ro) 查询 1.任意客户端2.任意的用户​ 服务端 showmout exportfs system ...

  3. Idea克隆检出git项目

    1.我这里假设你已经安装好了Idea和Git环境 2. .

  4. ssm框架使springmvc放行资源(java配置类)

    在springmvc中,如果配置了拦截所有请求交给springmvc处理,会出现一些静态web资源加载不出来的情况,或者想放行指定web资源可以通过修改通过修改配置达到相应目的,这里使用覆写WebMv ...

  5. 使用selenium grid实现下发任务到远程机器,远程执行测试用例

    背景: 1. UI自动化测试用例, 可能想要在不同版本.不同浏览器下执行 2. UI自动化测试用例较多的时候,耗时时间长,这个时候可以通过分散在不同的机器上执行,减少自动化测试时间 实现 通过sele ...

  6. ZYNQ:PetaLinux工程更新HDF文件的脚本

    PetaLinux工程更新HDF文件的脚本 参考:PetaLinux工程更新HDF文件的脚本 工程师可能同时使用多个Vivado工程,以便测试不同的硬件配置.如果能够让一个PetaLinux工程支持多 ...

  7. 【论文阅读】RAL2020: UFOMap An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown

    Last edited time: March 31, 2023 1:30 PM Reference and prenotes Paper link:https://ieeexplore.ieee.o ...

  8. SpringBoot打包maven仓库里面没有的包

    SpringBoot打包maven仓库里面没有的包 在遇到一些自定义的jar包,maven仓库里面没有这些包,但是发布线上时我们还是只想发布一个jar包,也就是我们想要把第三方包打在最后生成的大jar ...

  9. 全志A40i+Logos FPGA开发板(4核ARM Cortex-A7)硬件说明书(下)

    前 言 本文档主要介绍板卡硬件接口资源以及设计注意事项等内容,测试板卡为创龙科技旗下的全志A40i+Logos FPGA开发板. 核心板的ARM端和FPGA端的IO电平标准一般为3.3V,上拉电源一般 ...

  10. Linux运行等级

    Linux运行级别 Linux system存在7个运行级别 运行级别0:所有进程终止,机器将有序停止,关机时就处于这个运行级别 运行级别1:单用户模式(root用户进行维护),系统中所有的服务也不会 ...