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

# 光速上手 - JPA 原生 sql DTO 投影


                                                                     前言

        使用 JPA 时,我们一般通过 @Entity 进行实体类映射,从数据库中查询出对象。然而,在实际开发中,有时需要自定义查询结果并将其直接映射到 DTO,而不是实体类。这种需求可以通过 JPA 原生 SQL 查询和 DTO 投影 来实现。博主将以实际开发场景 为例,快速摘要如何在 JPA 中实现基于原生 SQL 的 DTO 投影



                                                                    开始 - 实现步骤

                                   以下是实现 DTO 投影的完整步骤,包括实体类、SQL 映射配置、接口调用和 DTO 设计。



一、配置实体类及映射

       首先在实体类中定义 @SqlResultSetMapping,用于将原生 SQL 查询结果映射到 DTO 类。在这个例子中,我们定义了 IssueVideo 实体,并通过 @SqlResultSetMapping@NamedNativeQuery 配置了一个纯sql查询


两个注解 详解 (已理解可以跳过)

  • 1. @NamedNativeQuery

    核心作用

    • @NamedNativeQuery 是用来定义 原生 SQL 查询 的。

    • 尽管JPA 中已经为sql 提供了许多方便的解决方式,但是某些场景下,我们还是需要直接使用原生 SQL , 例如:

      1. 数据查询逻辑复杂,无法用 JPQL 表达
      2. 涉及数据库特定的功能(如窗口函数、分区排序等)
      3. 查询结果无法直接映射到实体类(如 DTO、聚合结果)

       通过 @NamedNativeQuery,我们可以直接在实体类中绑定一个原生 SQL 查询,并为这个查询命名。在调用时,可以通过指定这个命名的查询名称直接执行该 SQL


  • 2. @SqlResultSetMapping
    核心作用

    • @SqlResultSetMapping 是用来定义 查询结果的映射 规则的。

    • 当我们使用原生 SQL 查询时,返回的结果是数据库的行列数据,与实体类的属性或 DTO 的结构未必完全匹配。

      @SqlResultSetMapping(name = "", ...) -> 它长这样
      

      它用来告诉 JPA:

      • 查询返回的列和 DTO 的字段如何一一对应
      • 如何将原生 SQL 查询的结果映射为自定义的类(DTO)

      ​         没有 @SqlResultSetMapping 时,JPA 会尝试将查询结果映射到实体类,但如果结果不是直接对应实体类那么映射就会失败。这时,我们就需要 @SqlResultSetMapping 来自定义映射规则。


  • 3. 为什么需要将它们写在实体类上?

    • 实体类是 SQL 映射的入口
             在 JPA 中,实体类是我们与数据库表交互的核心对象。因此:

      • @NamedNativeQuery@SqlResultSetMapping 写在实体类上,可以明确这段查询与该实体相关,方便维护和查阅。

      • JPA 的原生查询和结果映射机制依赖于实体类的原数据,通过注解绑定的方式,可以让这些查询和映射规则作为实体类的一部分,便于复用。

    • 关联性强

      • @NamedNativeQuery
               定义了原生 SQL 查询,而 @SqlResultSetMapping 定义了如何映射这个查询的结果,它们是 成对使用的。二者写在同一个实体类上,能清晰地表达“该查询和该实体类相关”的逻辑。

      • 如果你把它们分散到其他地方,可能会增加代码复杂性和维护成本。


  • 4. 总结

简单来说,@NamedNativeQuery@SqlResultSetMapping 分别解决了两个不同的问题:

  • @NamedNativeQuery 负责“如何查询
           它定义了 SQL 的逻辑以及参数。
  • @SqlResultSetMapping 负责“如何处理查询结果
           它定义了如何将 SQL 返回的数据映射到 DTO中

二者通过查询名称(name 属性)联系在一起。例如:

@NamedNativeQuery(name = "IssueRecommendRespDTOQuery", // 查询名称resultSetMapping = "IssueRecommendRespDTOResult", // 映射↓query = """SELECT ... -- 原生 SQL 查询"""
)
@SqlResultSetMapping(name = "IssueRecommendRespDTOResult", // 映射名称 对应↑classes = @ConstructorResult(targetClass = IssueRecommendRespDTO.class, // 映射到的 DTOcolumns = {@ColumnResult(name = "isdId", type = Integer.class),...})
)

两个注解解释 - end



实体类代码示例
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "issue_video")
// region jpa 投影主页查询目标dto (可以通过 "region <> endregion" 将其折叠起来)
@SqlResultSetMapping(name = "IssueRecommendRespDTOResult",classes = @ConstructorResult(targetClass = IssueRecommendRespDTO.class,columns = {@ColumnResult(name = "isdId", type = Integer.class),@ColumnResult(name = "videoUrl", type = String.class),@ColumnResult(name = "duration", type = Integer.class),@ColumnResult(name = "issId", type = Integer.class),@ColumnResult(name = "title", type = String.class),@ColumnResult(name = "cover", type = String.class),@ColumnResult(name = "watchNum", type = BigInteger.class),@ColumnResult(name = "commentNum", type = Integer.class),@ColumnResult(name = "creTime", type = LocalDateTime.class),@ColumnResult(name = "authorId", type = Integer.class),@ColumnResult(name = "authorName", type = String.class)})
)
// endregion// region jpa 投影主页推荐查询sql
@NamedNativeQuery(name = "IssueRecommendRespDTOQuery",resultSetMapping = "IssueRecommendRespDTOResult",query = """
SELECTsub.isd_id AS isdId,sub.video_url AS videoUrl,sub.duration AS duration,sub.iss_id AS issId,sub.title AS title,sub.cover AS cover,sub.watch_num AS watchNum,sub.comment_num AS commentNum,sub.cre_time AS creTime,sub.u_id AS authorId,sub.name AS authorNameFROM (SELECTi.score,v.isd_id,v.video_url,v.duration,i.iss_id,i.title,i.cover,i.watch_num,i.comment_num,i.cre_time,author.u_id,author.name,casewhen ROW_NUMBER() OVER (PARTITION BY i.su_idORDER BYCASEWHEN sp.su_id IS NOT NULL THEN (i.score + sp.score)ELSE i.scoreEND DESC) <= 3 then 1else 2end AS rank_within_partition,RANK() OVER (PARTITION BY i.su_idORDER BYCASEWHEN sp.su_id IS NOT NULL THEN (i.score + sp.score)ELSE i.scoreEND DESC) as global_rankFROM issue_video vJOIN issue i ON i.iss_id = v.iss_idJOIN user author ON author.u_id = i.u_idLEFT JOIN subarea_preference spON sp.su_id = i.su_idand sp.u_id = :uIdorder by (i.score + sp.score) desc) suborder by rank_within_partition, global_rank
"""
)
// endregion
public class IssueVideo {@GeneratedValue(strategy = GenerationType.IDENTITY)@Idprivate Integer isdId;private String videoUrl;private int duration;private int size;private LocalDateTime updTime;private String remark;private LocalDateTime issueTime;private String permission;private Boolean isDeclare;private Boolean offDanmu;private Boolean offComm;private Boolean onGretestComm;private Boolean isDel;@ManyToOne@JoinColumn(name = "vd_id")private VideoDeclare videoDeclare;private BigInteger danmuNum;@OneToOne@JoinColumn(name = "iss_id")private Issue issue;
}

二、配置对应 JPA 接口

       在 JPA 接口中,直接通过 @Query 注解调用刚刚定义的原生 SQL 查询,并将结果映射成期望的 DTO 返回类型

Repository 代码示例
public interface IssueVideoRepo extends JpaRepository<IssueVideo, Integer> {/*** 获取主页推荐视频* @param uId 用户 ID* @return DTO 列表*/@Query(name = "IssueRecommendRespDTOQuery", nativeQuery = true)List<IssueRecommendRespDTO> getRecommendVideos(@Param("uId") Integer uId);
}

三、事务层调用接口

       事务层负责调用 Repository 接口,并将返回的结果处理为最终服务层需要的数据。以下为服务实现代码:

Service 代码示例
@Service
public class IssueVideoServiceImpl implements IssueVideoService {@Autowiredprivate IssueVideoRepo issueVideoRepo;@Overridepublic List<IssueRecommendRespDTO> getRecommendVideos(Integer uId) {List<IssueRecommendRespDTO> recommendVideos = null;try {recommendVideos = issueVideoRepo.getRecommendVideos(uId);} catch (Exception exception) {exception.printStackTrace();}return recommendVideos;}
}

四、定义 DTO 类

       最后,定义与查询结果对应的 DTO 类。DTO 结构需要与 @SqlResultSetMapping 中的字段一一对应。

DTO 代码示例
@Data // 主dto 不需要lombok 全参数注解 @AllArgsConstructor, 因为要额外配置
public class IssueRecommendRespDTO {private Integer isdId;private String videoUrl;private Integer duration;private IssueRecommendInDTO issue;public IssueRecommendRespDTO() {}public IssueRecommendRespDTO(Integer isdId, String videoUrl, Integer duration,Integer issId, String title, String cover,BigInteger watchNum, Integer commentNum, LocalDateTime creTime,Integer authorId, String authorName) {this.isdId = isdId;this.videoUrl = videoUrl;this.duration = duration;this.issue = new IssueRecommendInDTO(issId, title, cover,watchNum, commentNum, creTime,new AuthorInDTO(authorId, authorName));}
}@AllArgsConstructor
@NoArgsConstructor
@Data
public class IssueRecommendInDTO { // In命名表示 该dto 很可能处于内部使用 > internal : 内部的private Integer issId;private String title;private String cover;private BigInteger watchNum;private Integer commentNum;private LocalDateTime creTime;private AuthorInDTO author;
}@AllArgsConstructor
@NoArgsConstructor
@Data
public class AuthorInDTO {private Integer authorId;private String authorName;
}

总结

       上述步骤以经过实际开发测试,保证有效!

  1. 高效性:直接通过原生 SQL 查询所需数据,减少不必要字段的查询和映射。
  2. 灵活性:可以自由定义 DTO 结构,满足复杂查询的需求。
  3. 可维护性:使用 @SqlResultSetMapping 将 SQL 与 Java 类关联,便于后续维护。

       该文章适用于需要自定义复杂查询且无需将查询结果绑定到实体类的场景。如果你也有类似需求,不妨以文章为参照上手试试!

end…

如果这篇文章帮到你, 帮忙点个关注呗, 不想那那那点赞或收藏也行鸭 (。•̀ᴗ-)✧ ~
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
                                                                                                                                   '(இ﹏இ`。)

相关文章:

# 光速上手 - JPA 原生 sql DTO 投影

前言 使用 JPA 时&#xff0c;我们一般通过 Entity 进行实体类映射&#xff0c;从数据库中查询出对象。然而&#xff0c;在实际开发中&#xff0c;有时需要自定义查询结果并将其直接映射到 DTO&#xff0c;而不是实体类。这种需求可以通过 JPA 原生 SQL 查询和 DTO 投影 来实现…...

ASP.NET Web应用程序出现Maximum request length exceeded报错

一、问题描述 在ASP.NET的web应用中&#xff0c;导出数据时出现500 - Internal server error.Maximum request length exceeded。 二、原因分析 这个错误通常出现在Web应用程序中&#xff0c;表示客户端发送的HTTP请求的长度超过了服务器配置的最大请求长度限制。这可能是因为…...

HTML——16.相对路径

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><a href"../../fj1/fj2/c.html" target"_blank">链接到c</a><!--相对路径&#xff1a;-->…...

windows 默认的消息ID有那些---我与大模型对话

前言&#xff1a; 与大模型交流&#xff0c;提问要尽量简短&#xff0c;突出关键词。否则它的回答就可能事是而非。用它总结和查资料还行&#xff0c;用它解决问题路还很远。它非常注重标准格式并机械的执行标准格式&#xff0c;并且事无巨细&#xff0c;不能灵活简要的回答问…...

CSV vs 数据库:爬虫数据存储的最佳选择是什么

介绍 在爬虫技术中&#xff0c;数据存储是一个不可缺少的环节。然而&#xff0c;选择合适的存储方式对数据分析和结果应用都致关重要。CSV和数据库是常用的两种存储方式&#xff0c;但它们各有优缺。这篇文章将分析两者在爬虫数据存储方面的选择值。 微博热搜是当前网络热点话…...

编译原理学习笔记——CH7-Runtime Environments运行时环境

本章重点&#xff1a; 为什么函数调用可以采用栈式存储&#xff1f; 函数调用和返回过程中需要记录哪些信息&#xff1f;如何记录&#xff1f; 主要知识点&#xff1a;  环境、状态、activation &#xff08;激活&#xff09; of procedures 、elaboration &#xff08;确立…...

机器学习DAY7: 特征工程和特征选择(数据预处理)(完)

本文通过特征提取、特征转换、特征选择三个过程介绍数据预处理方法&#xff0c;特征提取将原始数据转换为适合建模的特征&#xff0c;特征转换将数据进行变换以提高算法的准确性&#xff0c;特征选择用来删除无用的特征。 知识点 特征提取特征转换特征选择 本次实验的一些示…...

vue3动态加载组件

如何在Vue3中动态加载组件 需求根据下拉框的值&#xff0c;加载不同的组件 新建文件aaa.vue&#xff0c;bbb.vue <template><div class"container">我是bbbb组件</div> </template><script lang"ts" setup name"taskPus…...

12.29 redis缓存一致性

更新操作 如果先更新数据库再更新缓存 先更新缓存再更新数据库 更新缓存为1 更新缓存尾2 更新数据库为2 更新数据库为1 那么最后缓存为2 数据库为1 数据不一致 先更新数据库&#xff0c;再更新缓存 数据库为1 数据库为2 缓存为2 缓存为1 还是不一致 于是这种情况我们改为将缓…...

SqlSugar配置连接达梦数据库集群

安装达梦数据库时&#xff0c;会自动在当前操作系统中创建dm_svc.conf文件&#xff0c;可以在其中配置集群信息&#xff0c;不同操作系统下的文件位置如下图所示&#xff1a;   dm_svc.conf文件内的数据分为全局配置区域、服务配置区域&#xff0c;以参考文献1中的示例说明&…...

评分模型在路网通勤习惯分析中的应用——提出问题(1)

1、问题的由来、目标和意义 最近一段时间和公司其它业务部门讨论时&#xff0c;发现一个有趣的交通路网问题&#xff0c;车辆从S点行驶到V点共用时40分钟&#xff0c;这段时间内路网中的卡口摄像头识别到了车辆通过的信息。如下图所示&#xff1a; 设计师需要通过这些有限的路…...

使用 OpenCV 绘制线条和矩形

OpenCV 是一个功能强大的计算机视觉库&#xff0c;它不仅提供了丰富的图像处理功能&#xff0c;还支持图像的绘制。绘制简单的几何图形&#xff08;如线条和矩形&#xff09;是 OpenCV 中常见的操作。在本篇文章中&#xff0c;我们将介绍如何使用 OpenCV 在图像上绘制线条和矩形…...

npm 切换镜像源

设置镜像源 npm config set registry https://mirrors.huaweicloud.com/repository/npm/ npm 官方原始镜像网址是&#xff1a;https://registry.npmjs.org/ 淘宝 NPM 镜像&#xff1a;https://registry.npm.taobao.org 阿里云 NPM 镜像&#xff1a;https://npm.aliyun.com 腾…...

CSS(四)display和float

display display 属性用于控制元素的显示类型&#xff0c;用的 display 值包括&#xff1a; block&#xff1a;块级元素 使元素成为块级元素&#xff0c;占据一整行&#xff0c;前后有换行宽度默认为父容器的 100%&#xff0c;可以设置宽高&#xff0c;支持 margin、padding、…...

MMaudio AI:如何通过 AI 实现精准的视频到音频合成

1. 引言&#xff1a;视频音效制作的新纪元 无论是短视频创作者还是电影后期制作团队&#xff0c;音效始终是提升作品质量的关键。然而&#xff0c;手动调整音效不仅耗时&#xff0c;还容易出错。试想&#xff0c;如果一项 AI 技术能够根据视频内容自动生成与画面完美同步的音效…...

SQL进阶技巧:如何分析双重职务问题?

目录 0 背景描述 1 数据准备 2 问题分析 方法2:利用substr函数,充分利用数据特点【优秀解法】 3 小结...

OpenCV相机标定与3D重建(37)计算两幅图像之间单应性矩阵(Homography Matrix)的函数findHomography()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 找到两个平面之间的透视变换。 cv::findHomography 是 OpenCV 库中用于计算两幅图像之间单应性矩阵&#xff08;Homography Matrix&#xff09;的…...

Nacos配置管理+共享配置、配置热更新

1. 什么是配置管理? Nacos 配置管理是一个集中管理配置的工具。 它把微服务的配置集中存放&#xff0c;方便管理。可以动态更新配置&#xff0c;配置变了&#xff0c;微服务能马上知道并更新&#xff0c;不用重启。还能进行版本控制&#xff0c;记录配置的历史版本方便回滚。…...

asp.net core系统记录当前在线人数

实时记录当前在线人数&#xff0c;登录后保持120秒在线状态&#xff0c;在线状态保存在缓存中&#xff0c;采用滑动过期&#xff0c;在120秒内请求了系统&#xff0c;自动续活120秒&#xff1b;超过时间则移除用户在线状态&#xff1b; 需要在登录过滤器标记用户在线状态需要排…...

秒杀场景的设计思考

秒杀场景的设计思考 在学习Redis的之后&#xff0c;一个绕不开的话题就是秒杀系统的设计。本文将从下面&#x1f447;&#x1f3fb;几个方面展开一下个人简单的理解&#xff1a; 秒杀场景的介绍设计的核心思路怎么限流、削峰、异步planB总结 ‍ 秒杀场景的介绍 秒杀场景是…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...