函数指针使用场景和选择

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实体...相关推荐

  1. 选择排序_在N + 1场景中,使用@NamedEntityGraph更有选择地加载JPA实体

    选择排序 N + 1问题是使用ORM解决方案时的常见问题. 当您将某些@OneToMany关系的fetchType设置为lazy时,会发生这种情况,以便仅在访问Set / List时才加载子实体. 假 ...

  2. 在N + 1场景中使用@NamedEntityGraph更有选择地加载JPA实体

    N + 1问题是使用ORM解决方案时的常见问题. 当您将某些@OneToMany关系的fetchType设置为lazy时,会发生这种情况,以便仅在访问Set / List时才加载子实体. 假设我们有一 ...

  3. 动态加载子节点_简易数据分析 10 | Web Scraper 翻页—抓取「滚动加载」类型网页...

    这是简易数据分析系列的第 10 篇文章. 原文首发于博客园:简易数据分析 10. 友情提示:这一篇文章的内容较多,信息量比较大,希望大家学习的时候多看几遍. 我们在刷朋友圈刷微博的时候,总会强调一个『 ...

  4. div自动滚动_简易数据分析 10 | Web Scraper 翻页——抓取「滚动加载」类型网页

    这是简易数据分析系列的第 10 篇文章. 原文首发于博客园:简易数据分析 10. 友情提示:这一篇文章的内容较多,信息量比较大,希望大家学习的时候多看几遍. 我们在刷朋友圈刷微博的时候,总会强调一个『 ...

  5. nuxt解决首屏加载慢问题_滴普大前端 | 滴普是如何实现首屏加载性能优化的?...

    决定优化方向 首先打开 Inspect - Network 查看请求情况,从图片可以看出,DOMContentLoaded 时间为 2.67s,Load 时间为 3.45s,资源交换为 2.4MB. ...

  6. ensure函数_webpack中利用require.ensure()实现按需加载

    webpack中的require.ensure()可以实现按需加载资源包括js,css等,它会给里面require的文件单独打包,不和主文件打包在一起,webpack会自动配置名字,如0.js,1.j ...

  7. lstm中look_back的大小选择_基于机器学习检测僵尸网络中的域名生成算法

    0x01 Absert 恶意软件通常使用域名生成算法(DGA)作为联系其C&C服务器的机制.近年来,基于机器学习已经提出了不同的方法来自动检测生成的域名.但也存在一些问题.第一个问题是,由于缺 ...

  8. java 弹窗选择_如何在java中点击button弹出一个选择框

    展开全部 简要思e5a48de588b662616964757a686964616f31333332633064路: 声明一个类:public class DeptChooser extends JD ...

  9. mysqlit根据稀有值随机选择_洗练属性怎么选?看高级气功师如何选择

    本期内容我们将进一步为大家介绍一下宠物共鸣玩法中的洗练玩法,聊一聊气功师如何选择洗练属性. 共鸣水晶达到一定的条件,就可以开启共鸣轮盘,共鸣轮盘可以洗练属性,该属性将受到入住宠物评分的影响,入住宠物的 ...

最新文章

  1. IOS 编程中引用第三方的方类库的方法及常见问题
  2. ssh连接卡在【To escape to local shell, press ‘Ctrl+Alt+]‘.】的解决方法
  3. 森林病虫防治系统 (十一)
  4. python变量后面加星号_Python开发中关于参数使用的几点建议 -- 1
  5. SQLite和NPoco的数据库初始化器
  6. excel VB代码
  7. Android httpclient、json
  8. 计算机基础知识office软件,计算机基础知识和office办公系列软件的使用(完整版)...
  9. YOLOv2论文中英文对照翻译
  10. 2020年最新微博相关数据API+一站式获取个人微博信息+套娃、批量式获取微博用户信息
  11. 网络拓扑绘制软件亿图图示安装以及使用攻略
  12. TeachingKids-一款针对2到6岁宝宝的教育类游戏,目前可以让宝宝认知一些基础的水果,并进行简单的测验。
  13. 基于IIC和SPI协议的OLED显示(STM32)
  14. 云原生新边界——阿里云边缘计算云原生落地实践
  15. ArcToolbox的运行结果发布为GP服务
  16. 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler...
  17. 【408计算机考研】计算机网络——第1章 计算机网络体系结构
  18. 信息熵的由来、相关概念及思考
  19. Revit二次开发-自动线性尺寸标注
  20. mybatis 插件机制

热门文章

  1. P3701 -「伪模板」主席树【网络流,最大流】
  2. ssl1624-小萨的烦恼【图论,最短路,Floyd】
  3. 2020 China Collegiate Programming Contest Qinhuangdao Site 补题部分
  4. 【树形DP】没有上司的晚会 (ssl 1607)
  5. SpringCloud Zuul(八)之ERROR Filter
  6. 99%的面试官都会问到的Java面试题
  7. 上机不会做?在讲台上做做试试!
  8. 《四世同堂》金句摘抄(十七)
  9. 2015蓝桥杯省赛---java---A---2(星系炸弹)
  10. MyBatis_1 简介