当前位置: 首页 > article >正文

后端之JPA(EntityGraph+JsonView)

不同表之间的级联操作或者说关联查询是很多业务场景都会用到的。

对于这种需求最朴素的方法自然是手动写关联表,然后对被关联的表也是手动插入数据。但是手写容易最后写成一堆shit代码,而且修改起来也是非常麻烦的。

学会使用现成的工具还是非常有利的。接下来就来说一说JPA如何关联查询和实现级联操作。

@JsonManagedReference和@JsonBackReference

这两个注解配套使用,一般用在一对多关系,也就是外键级联操作。
在注解@OneToMany和@ManyToOne的基础上,一是用@JsonManagedReference,多用@JsonBackReference。同时也可以搭配其他的设置,如cascade和orphanRemoval来实现级联操作。

下面为一个示例
 

@Entity
@Data
@Table(name="math_questions")
public class Question {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)@JsonManagedReference("question-questionTags") // 指定唯一的引用名称private List<QuestionTag> questionTags = new ArrayList<>();
}
@Entity
@Data
@Table(name="tags")
public class Tag {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@OneToMany(mappedBy = "tag", cascade = CascadeType.ALL, orphanRemoval = true)@JsonManagedReference("tag-questionTags") // 指定唯一的引用名称private List<QuestionTag> questionTags = new ArrayList<>();
}
@Entity
@Data
@Table(name = "question_tag")
public class QuestionTag {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;  // 主键@ManyToOne@JoinColumn(name = "question_id")@JsonBackReference("question-questionTags") // 与 Question 中的 @JsonManagedReference 对应private Question question;@ManyToOne@JoinColumn(name = "tag_id")@JsonBackReference("tag-questionTags") // 与 Tag 中的 @JsonManagedReference 对应private Tag tag;
}

那为什么要用到这两个注解呢?直接使用@OneToMany和@ManyToOne不就可以实现级联操作了吗?原因是我这里用的是双向关联,也就是Question中有Question_tag,Tags中有Question_tag,而Question_tag中又有Question和Tags。这样就会导致查询的时候无限递归下去,查到任何一个都可以继续级联查下去。

所以使用@JsonManagedReference和@JsonBackReference可以做到只查一层,也就是对Question表操作,只会影响question_tag表。同样对tags表操作,也只会影响question_tag表。这样就不会一直递归下去。

@EntityGraph

但是这样在之后又遇到一个问题,那就是在使用@EntityGraph进行关联查询的时候,发现只能从question查询到question_tag,再往下就查询不到了,实际上也是查询到了,只不过是因为又@JsonManagedReference和@JsonBackReference导致在最后被过滤掉了。

于是我就在想,有没有一种办法,即能保证不无限递归下去,又能做到查询到我想要的结果:通过question查询到与之相关的标签?

@JsonIdentityInfo

之后发现用@JsonIdentityInfo可以在查询到无限递归时自动停下来。乍一听似乎很好,但实际操作结果是,可能会有很多层嵌套,只能说最后结果对了,但是基本不可操作。

    {"id": 17,"questionType": "LATEX","questionImagePath": null,"questionLatex": "测试添加标签","answerType": "BOTH","answerImagePath": "images/42f8099e-00ef-4485-a833-65541cb9b0d8_S2的配置命令.png","answerLatex": "1","uploadTime": "2025-02-24 11:25:41","lastPracticeTime": null,"correctCount": 0,"incorrectCount": 0,"questionTags": [{"id": 1,"question": 17,"tag": {"id": 1,"questionTags": [1,{"id": 2,"question": {"id": 19,"questionType": "LATEX","questionImagePath": null,"questionLatex": "多加一个标签","answerType": "LATEX","answerImagePath": null,"answerLatex": "现在是能搞到标签的id但是搞不到name","uploadTime": "2025-02-24 12:09:04","lastPracticeTime": null,"correctCount": 0,"incorrectCount": 0,"questionTags": [{"id": 3,"question": 19,"tag": {"id": 2,"questionTags": [3],"tag_name": "测试用例1"}},2]},"tag": 1}],"tag_name": "测试用例2"}}]},

这么深的嵌套就不说了,重复的内容还会再下次直接用数字代替,这不又得多建立一层映射关系,想想都麻烦。

最后感觉没啥办法了,想着保留级联操作,然后老老实实自己写SQL吧。手写的唯一好处就是可以定制化,虽然可能会有很多bug,不好维护,但是在功能都实现不了的情况下就不要求这么多了。 

不过,自己动手造轮子是不可能的,是绝对不允许的。

这不,又找到了一个不错的好玩意,起码能解决我的问题。依旧是使用cascade来保证级联操作。然后使用EntityGraph来关联查询。但是不使用@JsonManagedReference和@JsonBackReference,因为这个其实适用于比较有明显的主次关系的结构。我的业务两者只能说使用频率有差距,但地位是相同的。所以其实这个不合适。

那不使用@JsonManagedReference和@JsonBackReference如何保证不无限循环的呢?

答案是@JsonView

有点小麻烦,需要在每个字段都标注(不知道能不能批量标注),但是正因为是具体到每个字段,而且可以标注多个,就可以非常灵活的选择展示哪些,不展示哪些,进而避免双向关联的循环。说白了就是把DTO换成了注解。靠人工手动标注来防止出错。

起码,这个方法是解决了我的问题。

最后补充几点,上述被我否定的几种方法,不是不好,只是不适用于我的业务罢了。其实EntityGraph挺好的,就是搭配JsonView,可以做到类似版本控制,就是可以写多个controller,给每个controller不同的JsonView就行,不需要修改原有的就可以灵活调整展示内容,有点类似增量开发。

再说一句,JsonView不同模式之间可以继承挺不错的。

相关文章:

后端之JPA(EntityGraph+JsonView)

不同表之间的级联操作或者说关联查询是很多业务场景都会用到的。 对于这种需求最朴素的方法自然是手动写关联表&#xff0c;然后对被关联的表也是手动插入数据。但是手写容易最后写成一堆shit代码&#xff0c;而且修改起来也是非常麻烦的。 学会使用现成的工具还是非常有利的…...

linux--卡顿

1&#xff0c;swappiness swappiness是一个影响操作系统如何使用交换空间&#xff08;swap space&#xff09;的内核参数。它的值范围是从0到100&#xff0c;这个数值决定了系统将数据从物理内存&#xff08;RAM&#xff09;移动到交换分区或交换文件的倾向程度&#xff0c;交…...

【Python pro】函数

1、函数的定义及调用 1.1 为什么需要函数 提高代码复用性——封装将复杂问题分而治之——模块化利于代码的维护和管理 1.1.1 顺序式 n 5 res 1 for i in range(1, n1):res * i print(res) # 输出&#xff1a;1201.1.2 抽象成函数 def factorial(n):res 1for i in range(1…...

Docker 2025/2/24

用来快速构建、运行和管理应用的工具。帮助部署。 快速入门 代码略 解释 docker run :创建并运行一个容器&#xff0c;-d是让容器在后台运行 --name mysql :给容器起个名字&#xff0c;必须唯一 -p 3306:3306 :设置端口映射 -e KEYVALUE :是设置环境变量 mysql :指定运行的…...

4. 示例:创建带约束的随机地址生成器(范围0x1000-0xFFFF)

文章目录 前言代码示例&#xff1a;运行方法&#xff1a;查看结果&#xff1a;关键功能说明&#xff1a;扩展功能建议&#xff1a; 前言 以下是一个完整的SystemVerilog测试平台示例&#xff0c;包含约束随机地址生成、日志输出和波形生成功能&#xff1a; 代码示例&#xff1…...

爱普生SG-8101CE可编程晶振赋能智能手机的精准心脏

在智能手机高速迭代的今天&#xff0c;高性能、低功耗与小型化已成为核心诉求。智能手机作为人们生活中不可或缺的工具&#xff0c;需要在各种复杂场景下稳定运行。爱普生SG-8101CE可编程晶振凭借其卓越性能&#xff0c;成为智能手机中不可或缺的精密时钟源&#xff0c;为通信、…...

指针解剖学:穿透C/C++内存操作的核心密码与避坑指南

一、指针的本质与内存模型 指针是C/C的核心特性&#xff0c;本质是内存地址的变量化表示。每个变量在内存中占据连续的字节空间&#xff0c;地址是内存单元的唯一编号&#xff08;如0x0028FF40&#xff09;。指针变量存储的是目标数据的首地址&#xff0c;通过地址间接操作数据…...

Qt关于平滑滚动的使用QScroller及QScrollerProperties类说明

一、触控时代的滚动工具&#xff1a;QScroller类设计介绍 1.1 从机械滚轮到数字惯性 在触控设备普及前&#xff0c;滚动操作如同老式打字机的滚轴&#xff0c;只能通过鼠标滚轮或滚动条进行离散式控制。QScroller的出现如同给数字界面装上了"惯性飞轮"&#xff0c;…...

【音视频】编解码相关概念总结

NALU RTP PS流 三者总体关系 NALU在RTP中的应用&#xff1a;视频流的RTP传输通常将NALU作为基本的单元进行传输。每个RTP包携带一个或多个NALU&#xff0c;这些NALU包含了视频编码数据。RTP协议通过其头部信息&#xff08;如时间戳、序列号等&#xff09;帮助接收端重新排列和…...

Vue3 + Vite + TS,使用 配置项目别名属性:resolve

使用 resolve 配置全局项目路径别名 1.优化了开发中单页面引用其他模块的路径复杂性 2.妥妥解决了&#xff0c;组件复用当中提高开发效率 // 不使用配置 import { useStore } from ../../../stores // 使用配置 可根据开发者需求任意定义&#xff0c;较多 import { useStore…...

docker创建nginx

docker run -d -p 8080:80 --name my-nginx-container nginx docker&#xff1a;命令 run&#xff1a;命令 -d&#xff1a;在后台运行容器 -p&#xff1a;8080:80&#xff1a;将容器内部的80端口映射到宿主机的8080端口。 --name my-nginx-container&#xff1a;为容器指定一个…...

StableDiffusion打包 项目迁移 项目分发 1

文章目录 SD项目迁移前置知识webui-user.batwebui.batlaunch_utils.py 下一篇开始实践 SD项目迁移 显卡驱动更新&#xff1a;https://www.nvidia.cn/geforce/drivers/ 下载安装三个程序&#xff1a; python3.10.6: https://www.python.org/downloads/release/python-3106/gi…...

【数据结构进阶】哈希表

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 一、哈希表的概念 二、哈希函数的实现方法 1. 直接定址法 2. 除留余数法 三、哈希冲突 1. 开放定址法&#xff08;闭散列&#xff0…...

【蓝桥杯嵌入式】各模块学习总结

系列文章目录 留空 文章目录 系列文章目录前言一、LED模块1.1 赛题要求1.2 模块原理图1.3 编写代码1.4 赛题实战 二、LCD模块2.1 赛题要求2.2 模块原理图2.3 编写代码2.4 赛题实战 三、按键模块3.1 赛题要求3.2 模块原理图3.3 编写代码3.4 赛题实战 四、串口模块4.1 赛题要求4…...

Rust学习总结之-枚举

枚举是一个很多语言都有的功能&#xff0c;不过不同语言中其功能各不相同但是要表达的意思是一致的&#xff0c;枚举就是对于一个事物可以穷举出所有可能得值。比如说人的性别就可以用枚举&#xff0c;男人和女人两种。下面我们来学习Rust中的枚举。 一&#xff1a;枚举定义 …...

Linux系统管理(十七)——配置英伟达驱动、Cuda、cudnn、Conda、Pytorch、Pycharm等Python深度学习环境

文章目录 前言安装驱动下载安装Cuda编辑环境变量安装Cudnn安装conda验证安装成功配置conda镜像退出conda环境创建python环境查看当前conda环境激活环境安装python包安装pytorch 安装pycharm安装jupyter notebook 前言 深度学习和大语言模型的部署不免会用到Linux系统&#xff…...

SLAM算法工程师的技术图谱和学习路径

SLAM(Simultaneous Localization and Mapping)算法工程师是负责开发和实现用于机器人、自动驾驶车辆等领域的SLAM算法的专业人士。下面是SLAM算法工程师需要掌握的基础理论知识: 机器人运动学和动力学:理解机器人在空间中的运动方式和控制方法,包括轮式、蜘蛛腿、飞行器等…...

【第三天】零基础学习量化基础代码分析-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 记录量化基础代码总览引言基本概念量化投资 伪代码示例&#xff1a;量化投资模型框架总结 每日-往期回看 第一天零基础学量化基础知识点总览-持续更新 第二天零基础…...

深入了解 Python 中的 MRO(方法解析顺序)

文章目录 深入了解 Python 中的 MRO&#xff08;方法解析顺序&#xff09;什么是 MRO&#xff1f;如何计算 MRO&#xff1f;C3 算法的合并规则C3 算法的合并步骤示例&#xff1a;合并过程解析 MRO 解析失败的场景使用 mro() 方法查看 MRO示例 1&#xff1a;基本用法 菱形继承与…...

如何防止 Instagram 账号被盗用:安全设置与注意事项

如何防止 Instagram 账号被盗用&#xff1a;安全设置与注意事项 在这个数字化时代&#xff0c;社交媒体平台如 Instagram 已成为我们日常生活的一部分。然而&#xff0c;随着网络犯罪的增加&#xff0c;保护我们的在线账户安全变得尤为重要。以下是一些关键的安全设置和注意事…...

采样算法二:去噪扩散隐式模型(DDIM)采样算法详解教程

参考 https://arxiv.org/pdf/2010.02502 一、背景与动机 去噪扩散隐式模型&#xff08;DDIM&#xff09; 是对DDPM的改进&#xff0c;旨在加速采样过程同时保持生成质量。DDPM虽然生成效果优异&#xff0c;但其采样需迭代数百至数千次&#xff0c;效率较低。DDIM通过以下关键…...

各种类型网络安全竞赛有哪些 网络安全大赛的简称

本文是对入门学习的一些概念了解和一些常规场景记录 1.CTF&#xff08;capture the flag&#xff09;是夺旗赛的意思。 是网络安全技术人员之间进行攻防的比赛。 起源1996年DEFCON全球黑客大会&#xff0c;替代之前真实攻击的技术比拼。 (DEFCON极客大会诞生1993&#xff0c;…...

包子凑数——蓝桥杯真题Python

包子凑数 输入输出样例 示例 1 输入 2 4 5输出 6样例说明 凑不出的数目包括&#xff1a;1, 2, 3, 6, 7, 11。 示例 2 输入 2 4 6输出 INF样例说明 所有奇数都凑不出来&#xff0c;所以有无限多个 运行限制 最大运行时间&#xff1a;1s最大运行内存: 256M 最大公约数 最大公…...

网络通信/IP网络划分/子网掩码的概念和使用

文章目录 概述子网的考题子网掩码的历史有/无类地址子网划分!子网掩码超网技术/CIDR子网掩码和路由IP子网掩码定义 网络规划网络规划-拆子网网络规划-组超网子网划分案例 区分于其他特殊IP地址IP地址和网络地址子网掩码和网络地址子网掩码和广播地址 子网间的通信其他 概述 本…...

【前端】简单原生实例合集html,css,js

长期补充&#xff0c;建议关注收藏点赞。 目录 分栏input各种类型iframe表单拖拽 分栏 区分fieldset和framesetframeset是把浏览器窗口分成几个区域&#xff0c;每个区域分别放置一个html文档到对应的frame中&#xff0c;而且这个比例可以按住边栏进行调整col指定左右边栏的宽…...

MySQL--》如何在MySQL中打造高效优化索引

目录 初识索引 索引结构 性能分析 索引使用 最左前缀法则 SQL提示使用 覆盖索引使用 前缀索引使用 索引失效情况 初识索引 索引(index)&#xff1a;是帮助MySQL高效获取数据的数据结构(有序)&#xff0c;在数据之外数据库系统还维护着满足特定查找算法的数据结构&…...

盛京开源社区加入 GitCode,书写东北开源生态新篇章

在数字化转型与开源技术蓬勃发展的浪潮下&#xff0c;开源社区已成为推动技术创新的核心力量。盛京开源社区&#xff08;SJOSC&#xff09;作为沈阳地区的开源交流平台&#xff0c;始终致力于连接开发者、企业及高校&#xff0c;构建区域技术生态圈。 现在&#xff0c;盛京开源…...

HTML转义和反转义工具类

HTML转义和反转义工具类 package com.common.utils;import cn.hutool.http.HTMLFilter; import org.apache.commons.lang3.StringUtils;/*** 转义和反转义工具类** author lxx*/ public class EscapeUtil {public static final String RE_HTML_MARK "(<[^<]*?>…...

网络运维学习笔记(DeepSeek优化版)005网工初级(HCIA-Datacom与CCNA-EI)链路层发现协议与VLAN技术

文章目录 一、链路层发现协议1.1 思科CDP协议1.2 华为LLDP协议 二、VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;技术详解2.1 基本概念2.2 技术特性2.3 接口工作原理2.3.1 Access模式2.3.2 Trunk模式 2.4 厂商配置对比思科配置华为配置 2.5 …...

DeepSeek开源周Day4:三连发!突破 AI 训练瓶颈的立体解决方案,并行计算三剑客DualPipe、EPLB与Profile-data

项目地址&#xff1a; https://github.com/deepseek-ai/DualPipehttps://github.com/deepseek-ai/eplbhttps://github.com/deepseek-ai/profile-data 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (4/5)&#xff01; ​ ​ 一、背景概述 …...