jpa避免n+1_JPA技巧:避免N + 1选择问题
jpa避免n+1
介绍
像JPA这样的ORM框架通过帮助我们在对象<->关系数据映射期间避免了很多样板代码,从而简化了我们的开发过程。 但是,它们还给表带来了一些其他问题,N + 1是其中之一。 在本文中,我们将简要介绍该问题以及避免这些问题的一些方法。
问题
作为示例,我将使用在线图书订购应用程序的简化版本。 在这样的应用程序中,我可能会创建一个如下所示的实体来代表采购订单–
@Entity
public class PurchaseOrder {@Idprivate String id;private String customerId;@OneToMany(cascade = ALL, fetch = EAGER)@JoinColumn(name = "purchase_order_id")private List<PurchaseOrderItem> purchaseOrderItems = new ArrayList<>();
}
采购订单由订单ID,客户ID和要购买的一个或多个项目组成。 PurchaseOrderItem实体可能具有以下结构–
@Entity
public class PurchaseOrderItem {@Idprivate String id;private String bookId;
}
这些实体已经简化了很多,但是出于本文的目的,这是可以做到的。
现在假设我们需要找到一个客户的订单以在他们的采购订单历史记录中显示它们。 以下查询将用于此目的–
SELECTP
FROMPurchaseOrder P
WHEREP.customerId = :customerId
转换为SQL后,其外观如下所示–
selectpurchaseor0_.id as id1_1_,purchaseor0_.customer_id as customer2_1_
frompurchase_order purchaseor0_
wherepurchaseor0_.customer_id = ?
此查询将返回客户拥有的所有采购订单。 但是,为了获取订单项,JPA将为每个单独的订单发出单独的查询。 例如,如果某个客户有5个订单,那么JPA将发出5个附加查询以获取这些订单中包含的订单项。 这基本上被称为N + 1问题-1个查询以获取所有N个采购订单,N个查询以获取所有订单商品。
当我们的数据增长时,此行为为我们带来了可伸缩性问题。 即使适量的订单和项目也会造成严重的性能问题。
解决方案
避免热切获取
这是问题背后的主要原因。 我们应该摆脱从映射中获取的所有渴望。 它们几乎没有任何好处可证明其可用于生产级应用程序。 我们应该将所有关系标记为“懒惰”。
需要注意的重要一点–将关系映射标记为“惰性”并不保证基础持久性提供程序也将其同样对待。 JPA规范不保证延迟获取。 充其量对持久提供者来说是一个提示。 但是,考虑到Hibernate,我从未见过这样做。
仅获取实际需要的数据
始终建议使用此方法,而不考虑是否要进行急切/懒惰的访存。
我记得我进行过一次N + 1优化,将REST端点的最大响应时间从17分钟提高到1.5秒 。 端点根据某些条件获取单个实体,对于我们当前的示例,该实体将遵循以下原则:
TypedQuery<PurchaseOrder> jpaQuery = entityManager.createQuery("SELECT P FROM PurchaseOrder P WHERE P.customerId = :customerId", PurchaseOrder.class);
jpaQuery.setParameter("customerId", "Sayem");
PurchaseOrder purchaseOrder = jpaQuery.getSingleResult();// after some calculation
anotherRepository.findSomeStuff(purchaseOrder.getId());
id是结果中唯一用于后续计算的数据。
有几个客户有上千个订单。 每个命令依次又有数千个其他几种不同类型的子级。 不用说,每当在此端点接收到针对这些订单的请求时,数据库中就会执行数千个查询。
为了提高性能,我所做的就是-
TypedQuery<String> jpaQuery = entityManager.createQuery("SELECT P.id FROM PurchaseOrder P WHERE P.customerId = :customerId", String.class);
jpaQuery.setParameter("customerId", "Sayem");
String orderId = jpaQuery.getSingleResult();// after some calculation
anotherRepository.findSomeStuff(orderId);
只是此更改导致680倍的改进 。
如果我们要获取多个属性,则可以利用JPA提供的Constructor表达式–
"SELECT " +
"NEW com.codesod.example.jpa.nplusone.dto.PurchaseOrderDTO(P.id, P.orderDate) " +
"FROM " +
"PurchaseOrder P " +
"WHERE " +
"P.customerId = :customerId",
PurchaseOrderDTO.class);
jpaQuery.setParameter("customerId", "Sayem");
List<PurchaseOrderDTO> orders = jpaQuery.getResultList();
使用构造函数表达式的一些注意事项–
- 目标DTO必须具有其参数列表与要选择的列匹配的构造函数
- 必须指定DTO类的完全限定名称
使用联接提取/实体图
每当我们需要同时获取带有所有子元素的实体时,就可以在查询中使用JOIN FETCH 。 这样可以减少数据库流量,从而提高性能。
JPA 2.1规范引入了实体图,它使我们能够创建静态/动态查询负载计划。
Thorben Janssen ( 这里和这里 )写了几篇文章,详细介绍了它们的用法,值得一看。
这篇文章的一些示例代码可以在Github上找到。
翻译自: https://www.javacodegeeks.com/2018/04/jpa-tips-avoiding-the-n-1-select-problem.html
jpa避免n+1
jpa避免n+1_JPA技巧:避免N + 1选择问题相关推荐
- 3DMAX的用途,游戏建模高效学习技巧,高薪职位选择
首先我们要清楚的是行业划分.3DMAX的用途非常广泛,所涉及的行业大致有,游戏建模,园林景观.城市规划.建筑设计.室内设计.动漫设计.商业动画制作等.所以我们在入手学3DMAX软件时,大家应该分清楚, ...
- 除了不要 SELECT * ,数据库还有哪些技巧
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:AIOps 应用程序慢如牛,原因多多,可能是网络的原因.可能 ...
- 提升Kaggle模型的实用小技巧!
↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 译者:张峰,Datawhale成员 如果你最近刚入手Kaggle,或者你 ...
- 《企业云桌面实施》-小技巧-04-VMWare Workstation-虚拟机强行关机开机
<企业云桌面实施>-系列博文-陆续更新中 <企业云桌面实施>-小技巧-01-规划注意事项 http://dynamic.blog.51cto.com/711418/188492 ...
- Google搜索技巧-从入门到精通(从此学习进步、工作顺心)
转载:http://www.blogbus.com/koudaizhi-logs/55687286.html 一 GOOGLE简介 Google (www.google.com)是一个搜寻引擎, ...
- 【Python基础】5个Pandas技巧
作者 | RAM DEWANI 编译 | VK 来源 | Analytics Vidhya 概述 Pandas提供了许多技术,使Python中的数据分析更容易 我们将讨论一些技巧,帮助你成为一个更好. ...
- 《企业云桌面实施》-小技巧-02-使用ISO光驱安装esxi6.5
<企业云桌面实施>-系列博文-陆续更新中 <企业云桌面实施>-小技巧-01-规划注意事项 http://dynamic.blog.51cto.com/711418/188492 ...
- 计算机背板知识,你知道背板的选购技巧吗?
原标题:你知道背板的选购技巧吗? 背板就是母板,子板插在上面构成系统,计算机背板说成背板也成立,只不过背板更多的知识线路板而已,没有实际的器件,只起信号通路作用.背板在设备机箱的后面.一般背板上都是设 ...
- 新版火狐浏览器怎么调整字体 火狐浏览器字体调整技巧分享
相信有了解的朋友都清楚,官方在新版火狐浏览器中不仅优化了UI设计,还带来了一些细微的变化与改进.那么,新版火狐浏览器该怎么调整字体呢?下面小编就来分享一下火狐浏览器字体调整技巧,有需要的朋友可以稍作参 ...
最新文章
- win10虚拟机服务器错误怎么解决方法,虚拟机下安装win10系统后出现升级报错故障的解决方法【图文】...
- .NET(C#):XmlArrayItem特性和XmlElement特性在序列化数组的差别
- c++ 结构体初始化_C/C++编程笔记:C语言和C++语言的 struct 对比!区别在哪里?
- linux下源码安装apache服务
- springmvc mybatis redis mysql maven搭建基本开发框架 (二)
- Vue中常用的组件传值方式
- 14-微信小程序商城 产品详情页布局(微信小程序商城开发、小程序毕业设计、小程序源代码)(黄菊华-微信小程序开发教程)
- Waves 13:一款专业电子音频制作插件和音频信号处理器插件套装
- 解决亚马逊购买的电子书azw3文件转换成epub或mobi文件实现共享
- 手机抓包软件:charles安装及教程
- Pyinstaller打包
- 手写vue3源码——reactive, effect ,scheduler, stop 等
- MenuetOS-令人不可思议的64位操作系统!
- 基于JS 高德地图设置设备图标
- postman使用pre-request script计算md5
- 多旋翼无人机组合导航系统-多源信息融合算法附Matlab代码
- 学生信息管理系统——顺序表
- 英语长语法难句——状语和状语从句
- PostGIS教程十三:地理
- CSS立体文字和电子数字样式数字大屏数字
热门文章
- P4022-[CTSC2012]熟悉的文章【广义SAM,dp,单调队列】
- P7324-[WC2021]表达式求值【dp】
- P4549-[模板]裴蜀定理
- ssl1213-多边形面积【差积,计算几何】
- codeforces1471 D. Strange Definition
- 【dfs】拔河比赛(ybtoj dfs-1-1)
- 【SPFA】Party(jzoj 1328)
- 动态规划训练10 [Coloring Brackets CodeForces - 149D]
- OAuth2 实现单点登录 SSO
- 当你「ping 一下」的时候,你知道它背后的逻辑吗