函数指针使用场景和选择_在N + 1场景中使用@NamedEntityGraph更有选择地加载JPA实体...
函数指针使用场景和选择
N + 1问题是使用ORM解决方案时的常见问题。 当您将某些@OneToMany关系的fetchType设置为lazy时,就会发生这种情况,以便仅在访问Set / List时才加载子实体。 假设我们有一个具有两个关系的Customer实体:每个客户的一组订单和一组地址。
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<OrderEntity> orders;@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<AddressEntity> addresses;
要加载所有客户,我们可以发出以下JPQL语句,然后加载每个客户的所有订单:
List<CustomerEntity> resultList = entityManager.createQuery("SELECT c FROM CustomerEntity AS c", CustomerEntity.class).getResultList();
for(CustomerEntity customerEntity : resultList) {Set<OrderEntity> orders = customerEntity.getOrders();for(OrderEntity orderEntity : orders) {...}
}
Hibernate 4.3.5(与JBoss AS Wildfly 8.1.0CR2一起提供)将从数据库中仅为两个(!)客户生成以下一系列SQL语句:
Hibernate: selectcustomeren0_.id as id1_1_,customeren0_.name as name2_1_,customeren0_.numberOfPurchases as numberOf3_1_ fromCustomerEntity customeren0_
Hibernate: selectorders0_.CUSTOMER_ID as CUSTOMER4_1_0_,orders0_.id as id1_2_0_,orders0_.id as id1_2_1_,orders0_.campaignId as campaign2_2_1_,orders0_.CUSTOMER_ID as CUSTOMER4_2_1_,orders0_.timestamp as timestam3_2_1_ fromOrderEntity orders0_ whereorders0_.CUSTOMER_ID=?
Hibernate: selectorders0_.CUSTOMER_ID as CUSTOMER4_1_0_,orders0_.id as id1_2_0_,orders0_.id as id1_2_1_,orders0_.campaignId as campaign2_2_1_,orders0_.CUSTOMER_ID as CUSTOMER4_2_1_,orders0_.timestamp as timestam3_2_1_ fromOrderEntity orders0_ whereorders0_.CUSTOMER_ID=?
如我们所见,第一个查询从表CustomerEntity中选择所有客户。 接下来的两个选择先提取,然后在第一个查询中加载我们已加载的每个客户的订单。 当我们有100个客户而不是2个客户时,我们将获得101个查询。 一个初始查询可加载所有客户,然后针对100个客户中的每个客户,另外查询一个订单。 这就是为什么将此问题称为N + 1的原因。
解决此问题的常见习惯是强制ORM生成内部联接查询。 在JPQL中,这可以通过使用JOIN FETCH子句来完成,如以下代码片段所示:
entityManager.createQuery("SELECT c FROM CustomerEntity AS c JOIN FETCH c.orders AS o", CustomerEntity.class).getResultList();
正如预期的那样,ORM现在使用OrderEntity表生成一个内部联接,因此只需要一个SQL语句即可加载所有数据:
selectcustomeren0_.id as id1_0_0_,orders1_.id as id1_1_1_,customeren0_.name as name2_0_0_,orders1_.campaignId as campaign2_1_1_,orders1_.CUSTOMER_ID as CUSTOMER4_1_1_,orders1_.timestamp as timestam3_1_1_,orders1_.CUSTOMER_ID as CUSTOMER4_0_0__,orders1_.id as id1_1_0__
fromCustomerEntity customeren0_
inner joinOrderEntity orders1_on customeren0_.id=orders1_.CUSTOMER_ID
在您知道必须为每个客户加载所有订单的情况下,JOIN FETCH子句将SQL语句的数量从N + 1减少到1。这当然具有缺点,即您现在要转移一个订单的所有订单。客户一次又一次的客户数据(由于查询中的其他客户列)。
JPA规范从版本2.1引入,即所谓的NamedEntityGraphs。 通过此批注,您可以描述JPQL查询应加载的图形,而不是JOIN FETCH子句可以执行的图形,从而为N + 1问题提供了另一种解决方案。 下面的示例演示了我们的客户实体的NamedEntityGraph,该实体应该仅加载客户名称及其订单。 订单在子图ordersGraph中有更详细的描述。 在这里,我们看到我们只想加载订单的字段ID和CampaignId。
@NamedEntityGraph(name = "CustomersWithOrderId",attributeNodes = {@NamedAttributeNode(value = "name"),@NamedAttributeNode(value = "orders", subgraph = "ordersGraph")},subgraphs = {@NamedSubgraph(name = "ordersGraph",attributeNodes = {@NamedAttributeNode(value = "id"),@NamedAttributeNode(value = "campaignId")})}
)
在通过NameManager通过EntityManager加载JPQL查询后,将其命名为JPQL查询的提示:
EntityGraph entityGraph = entityManager.getEntityGraph("CustomersWithOrderId");
entityManager.createQuery("SELECT c FROM CustomerEntity AS c", CustomerEntity.class).setHint("javax.persistence.fetchgraph", entityGraph).getResultList();
Hibernate从版本4.3.0.CR1开始支持@NamedEntityGraph批注,并为上面显示的JPQL查询创建以下SQL语句:
Hibernate: selectcustomeren0_.id as id1_1_0_,orders1_.id as id1_2_1_,customeren0_.name as name2_1_0_,customeren0_.numberOfPurchases as numberOf3_1_0_,orders1_.campaignId as campaign2_2_1_,orders1_.CUSTOMER_ID as CUSTOMER4_2_1_,orders1_.timestamp as timestam3_2_1_,orders1_.CUSTOMER_ID as CUSTOMER4_1_0__,orders1_.id as id1_2_0__ fromCustomerEntity customeren0_ left outer joinOrderEntity orders1_ on customeren0_.id=orders1_.CUSTOMER_ID
我们看到Hibernate不会发出N + 1查询,而是@NamedEntityGraph注释强制Hibernate为每个左外部联接加载订单。 当然,这与FETCH JOIN子句有微妙的区别,在子句中,Hibernate创建了内部联接。 与FETCH JOIN子句相反,左外部联接还将加载不存在订单的客户,在FETCH JOIN子句中,我们仅加载具有至少一个订单的客户。
有趣的是,Hibernate加载的负载比表CustomerEntity和OrderEntity的指定属性更多。 由于这与@NamedEntityGraph的规范(第3.7.4节)相冲突,因此我为此创建了一个JIRA问题 。
结论
我们已经看到,在JPA 2.1中,我们为N + 1问题提供了两种解决方案:我们可以使用FETCH JOIN子句来急切地获取一个@OneToMany关系,这将导致一个内部联接,或者我们可以使用@NamedEntityGraph功能使我们通过左外部联接指定要加载的@OneToMany关系。
翻译自: https://www.javacodegeeks.com/2014/07/using-namedentitygraph-to-load-jpa-entities-more-selectively-in-n1-scenarios.html
函数指针使用场景和选择
函数指针使用场景和选择_在N + 1场景中使用@NamedEntityGraph更有选择地加载JPA实体...相关推荐
- 选择排序_在N + 1场景中,使用@NamedEntityGraph更有选择地加载JPA实体
选择排序 N + 1问题是使用ORM解决方案时的常见问题. 当您将某些@OneToMany关系的fetchType设置为lazy时,会发生这种情况,以便仅在访问Set / List时才加载子实体. 假 ...
- 在N + 1场景中使用@NamedEntityGraph更有选择地加载JPA实体
N + 1问题是使用ORM解决方案时的常见问题. 当您将某些@OneToMany关系的fetchType设置为lazy时,会发生这种情况,以便仅在访问Set / List时才加载子实体. 假设我们有一 ...
- 动态加载子节点_简易数据分析 10 | Web Scraper 翻页—抓取「滚动加载」类型网页...
这是简易数据分析系列的第 10 篇文章. 原文首发于博客园:简易数据分析 10. 友情提示:这一篇文章的内容较多,信息量比较大,希望大家学习的时候多看几遍. 我们在刷朋友圈刷微博的时候,总会强调一个『 ...
- div自动滚动_简易数据分析 10 | Web Scraper 翻页——抓取「滚动加载」类型网页
这是简易数据分析系列的第 10 篇文章. 原文首发于博客园:简易数据分析 10. 友情提示:这一篇文章的内容较多,信息量比较大,希望大家学习的时候多看几遍. 我们在刷朋友圈刷微博的时候,总会强调一个『 ...
- nuxt解决首屏加载慢问题_滴普大前端 | 滴普是如何实现首屏加载性能优化的?...
决定优化方向 首先打开 Inspect - Network 查看请求情况,从图片可以看出,DOMContentLoaded 时间为 2.67s,Load 时间为 3.45s,资源交换为 2.4MB. ...
- ensure函数_webpack中利用require.ensure()实现按需加载
webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...
- lstm中look_back的大小选择_基于机器学习检测僵尸网络中的域名生成算法
0x01 Absert 恶意软件通常使用域名生成算法(DGA)作为联系其C&C服务器的机制.近年来,基于机器学习已经提出了不同的方法来自动检测生成的域名.但也存在一些问题.第一个问题是,由于缺 ...
- java 弹窗选择_如何在java中点击button弹出一个选择框
展开全部 简要思e5a48de588b662616964757a686964616f31333332633064路: 声明一个类:public class DeptChooser extends JD ...
- mysqlit根据稀有值随机选择_洗练属性怎么选?看高级气功师如何选择
本期内容我们将进一步为大家介绍一下宠物共鸣玩法中的洗练玩法,聊一聊气功师如何选择洗练属性. 共鸣水晶达到一定的条件,就可以开启共鸣轮盘,共鸣轮盘可以洗练属性,该属性将受到入住宠物评分的影响,入住宠物的 ...
最新文章
- IOS 编程中引用第三方的方类库的方法及常见问题
- ssh连接卡在【To escape to local shell, press ‘Ctrl+Alt+]‘.】的解决方法
- 森林病虫防治系统 (十一)
- python变量后面加星号_Python开发中关于参数使用的几点建议 -- 1
- SQLite和NPoco的数据库初始化器
- excel VB代码
- Android httpclient、json
- 计算机基础知识office软件,计算机基础知识和office办公系列软件的使用(完整版)...
- YOLOv2论文中英文对照翻译
- 2020年最新微博相关数据API+一站式获取个人微博信息+套娃、批量式获取微博用户信息
- 网络拓扑绘制软件亿图图示安装以及使用攻略
- TeachingKids-一款针对2到6岁宝宝的教育类游戏,目前可以让宝宝认知一些基础的水果,并进行简单的测验。
- 基于IIC和SPI协议的OLED显示(STM32)
- 云原生新边界——阿里云边缘计算云原生落地实践
- ArcToolbox的运行结果发布为GP服务
- 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler...
- 【408计算机考研】计算机网络——第1章 计算机网络体系结构
- 信息熵的由来、相关概念及思考
- Revit二次开发-自动线性尺寸标注
- mybatis 插件机制
热门文章
- P3701 -「伪模板」主席树【网络流,最大流】
- ssl1624-小萨的烦恼【图论,最短路,Floyd】
- 2020 China Collegiate Programming Contest Qinhuangdao Site 补题部分
- 【树形DP】没有上司的晚会 (ssl 1607)
- SpringCloud Zuul(八)之ERROR Filter
- 99%的面试官都会问到的Java面试题
- 上机不会做?在讲台上做做试试!
- 《四世同堂》金句摘抄(十七)
- 2015蓝桥杯省赛---java---A---2(星系炸弹)
- MyBatis_1	简介