eager_EAGER的获取是代码的味道

eager

介绍

Hibernate获取策略确实可以使几乎没有爬网的应用程序和响应Swift的应用程序有所不同。 在这篇文章中,我将解释为什么您应该选择基于查询的获取而不是全局获取计划。

取得101

Hibernate定义了四种关联检索策略 :

提取策略 描述
加入 原始SELECT语句中的关联是OUTER JOINED
选择 附加的SELECT语句用于检索关联的实体(实体)
子选择 附加的SELECT语句用于检索整个关联的集合。 此模式适用于多个关联
批量 其他数量的SELECT语句用于检索整个关联的集合。 每个其他的SELECT都会检索固定数量的关联实体。 此模式适用于多个关联


这些获取策略可能适用于以下情况:

  • 关联总是与其所有者一起初始化(例如EAGER FetchType)
  • 导航未初始化的关联(例如LAZY FetchType),因此必须使用辅助SELECT检索该关联

Hibernate映射获取信息形成了全局获取计划 。 在查询时,我们可以覆盖全局获取计划,但仅适用于LAZY关联 。 为此,我们可以使用访存HQL / JPQL / Criteria指令。 EAGER关联不能被覆盖,因此将您的应用程序与全局获取计划绑定在一起。

Hibernate 3承认LAZY应该是默认的关联获取策略:

默认情况下,Hibernate3对集合使用延迟选择获取,对单值关联使用延迟代理获取。 对于大多数应用程序中的大多数关联而言,这些默认设置有意义。

在注意到与Hibernate 2默认渴望获取有关的许多性能问题后,做出了此决定。 不幸的是,JPA采取了不同的方法,并决定对许多关联为LAZY,而渴望获得一对一的关系。

关联类型 默认提取策略
@OneTMany
@多多多
@多多 急于
@OneToOne 急于

EAGER获取不一致

尽管将关联标记为EAGER(将获取职责委托给Hibernate)可能很方便,但还是建议使用基于查询的获取计划。

始终会获取EAGER关联,并且获取策略在所有查询技术之间均不一致。

接下来,我将演示EAGER的获取对于所有Hibernate查询变量的行为。 我将重用我先前在获取策略文章中介绍的实体模型:

产品2

产品实体具有以下关联:

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "company_id", nullable = false)
private Company company;@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "product", optional = false)
private WarehouseProductInfo warehouseProductInfo;@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "importer_id")
private Importer importer;@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "product", orphanRemoval = true)
@OrderBy("index")
private Set<Image> images = new LinkedHashSet<Image>();

公司协会被标记为EAGER,并且Hibernate将始终采用获取策略来对其及其所有者实体进行初始化。

持久性上下文加载

首先,我们将使用Persistence Context API加载实体:

Product product = entityManager.find(Product.class, productId);

它将生成以下SQL SELECT语句:

Query:{[
select product0_.id as id1_18_1_, product0_.code as code2_18_1_, product0_.company_id as company_6_18_1_, product0_.importer_id as importer7_18_1_, product0_.name as name3_18_1_, product0_.quantity as quantity4_18_1_, product0_.version as version5_18_1_, company1_.id as id1_6_0_, company1_.name as name2_6_0_ 
from Product product0_ 
inner join Company company1_ on product0_.company_id=company1_.id 
where product0_.id=?][1]

使用内部联接检索了EAGER公司关联。 对于M个这样的关联,所有者实体表将被连接M次。

每个额外的联接加起来将增加总体查询复杂度和执行时间。 如果我们甚至在所有可能的业务场景中都没有使用所有这些关联,那么我们只是付出了额外的性能损失,却没有得到任何回报。

使用JPQL和条件进行获取

Product product = entityManager.createQuery("select p " +"from Product p " +"where p.id = :productId", Product.class).setParameter("productId", productId).getSingleResult();

或搭配

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Product> cq = cb.createQuery(Product.class);
Root<Product> productRoot = cq.from(Product.class);
cq.where(cb.equal(productRoot.get("id"), productId));
Product product = entityManager.createQuery(cq).getSingleResult();

生成以下SQL SELECT语句:

Query:{[
select product0_.id as id1_18_, product0_.code as code2_18_, product0_.company_id as company_6_18_, product0_.importer_id as importer7_18_, product0_.name as name3_18_, product0_.quantity as quantity4_18_, product0_.version as version5_18_ 
from Product product0_ 
where product0_.id=?][1]} Query:{[
select company0_.id as id1_6_0_, company0_.name as name2_6_0_ 
from Company company0_ 
where company0_.id=?][1]}

JPQL和Criteria查询都默认选择获取,因此为每个单独的EAGER关联发布辅助选择。 关联数越大,单个SELECTS越多,对我们应用程序性能的影响就越大。

Hibernate标准API

JPA 2.0添加了对Criteria查询的支持,而Hibernate长期以来一直提供特定的动态查询实现 。

如果EntityManager实现委托方法调用旧版Session API,则JPA Criteria实现是从头开始编写的。 这就是为什么Hibernate和JPA Criteria API在类似的查询方案中表现不同的原因。

前面的示例Hibernate Criteria等效项如下所示:

Product product = (Product) session.createCriteria(Product.class).add(Restrictions.eq("id", productId)).uniqueResult();

关联SQL SELECT是:

Query:{[
select this_.id as id1_3_1_, this_.code as code2_3_1_, this_.company_id as company_6_3_1_, this_.importer_id as importer7_3_1_, this_.name as name3_3_1_, this_.quantity as quantity4_3_1_, this_.version as version5_3_1_, hibernatea2_.id as id1_0_0_, hibernatea2_.name as name2_0_0_ 
from Product this_ 
inner join Company hibernatea2_ on this_.company_id=hibernatea2_.id 
where this_.id=?][1]}

此查询使用连接抓取策略,而不是选择抓取,通过JPQL / HQL和标准的API使用。

Hibernate条件和多个EAGER集合

让我们看看将图像收集获取策略设置为EAGER时会发生什么:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "product", orphanRemoval = true)
@OrderBy("index")
private Set<Image> images = new LinkedHashSet<Image>();

将生成以下SQL:

Query:{[
select this_.id as id1_3_2_, this_.code as code2_3_2_, this_.company_id as company_6_3_2_, this_.importer_id as importer7_3_2_, this_.name as name3_3_2_, this_.quantity as quantity4_3_2_, this_.version as version5_3_2_, hibernatea2_.id as id1_0_0_, hibernatea2_.name as name2_0_0_, images3_.product_id as product_4_3_4_, images3_.id as id1_1_4_, images3_.id as id1_1_1_, images3_.index as index2_1_1_, images3_.name as name3_1_1_, images3_.product_id as product_4_1_1_ 
from Product this_ 
inner join Company hibernatea2_ on this_.company_id=hibernatea2_.id 
left outer join Image images3_ on this_.id=images3_.product_id 
where this_.id=? 
order by images3_.index][1]}

Hibernate条件不会自动将父实体列表分组。 由于存在一对多子表JOIN,因此对于每个子实体,我们将获得一个新的父实体对象引用(在我们当前的持久性上下文中,它们均指向同一对象):

product.setName("TV");
product.setCompany(company);Image frontImage = new Image();
frontImage.setName("front image");
frontImage.setIndex(0);Image sideImage = new Image();
sideImage.setName("side image");
sideImage.setIndex(1);product.addImage(frontImage);
product.addImage(sideImage);List products = session.createCriteria(Product.class).add(Restrictions.eq("id", productId)).list();
assertEquals(2, products.size());
assertSame(products.get(0), products.get(1));

因为我们有两个图像实体,所以我们将获得两个Product实体引用,它们均指向同一一级缓存条目。

要解决此问题,我们需要指示Hibernate标准使用不同的根实体:

List products = session.createCriteria(Product.class).add(Restrictions.eq("id", productId)).setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY).list();
assertEquals(1, products.size());

结论

EAGER的获取策略是一种代码味道。 通常,它是出于简化的目的而使用的,而没有考虑长期的性能损失。 提取策略绝不应成为实体映射的责任。 每个业务用例具有不同的实体负载要求,因此,应将获取策略委托给每个单独的查询。

全局获取计划应仅定义LAZY关联,这些关联是在每个查询的基础上获取的。 结合始终检查生成的查询策略 ,基于查询的获取计划可以提高应用程序性能并降低维护成本。

  • Hibernate和JPA可用的代码。

翻译自: https://www.javacodegeeks.com/2014/12/eager-fetching-is-a-code-smell.html

eager

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么时候会是用treeset?_flex:1 到底代表什么?

今天在做项目的时候遇到一个关于布局的问题, 就是 flex: 1; 我一直以为 flex: 1; 代表的是 flex: aoto; 后来发现结果并不是这样, 所以写一篇博客来讲解一下 flex: 1; 代表什么代码第一版<div class"container"><div class"div">我是一个div&l…

纠缠不清的C语言位域(位段)详解

位域是什么&#xff1f;有些数据在存储时并不需要占用一个完整的字节&#xff0c;只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态&#xff0c;用 0 和 1 表示足以&#xff0c;也就是用一个二进位。正是基于这种考虑&#xff0c;C语言又提供了一种叫做位域的…

matlab画累计直方图_科学网—matlab 绘制直方图——常用命令 - 范凯波的博文

直方图上显示数值close all ,x rand(100,1);%获得直方图的数据[n,y] hist(x);maxN max(n);%设置显示x,y长度限制axis([0 1.2 0 maxN2])%根据直方图的数据绘制出图形bar(y,n);for i 1:length(y)%直方图上面数据对不齐&#xff0c;利用水平和垂直对齐 &#xff0c;可以参考se…

玩转java并发工具_玩Java并发

玩转java并发工具最近&#xff0c;我需要将一些文件&#xff08;每个文件都有JSON格式的对象列表&#xff08;数组&#xff09;&#xff09;转换为每个文件都具有相同数据&#xff08;对象&#xff09;的分隔行的文件。 这是一次性的任务&#xff0c;很简单。 我使用Java nio的…

django debug=false后静态文件丢失_python框架Django实战商城项目之工程搭建

项目说明 该电商项目类似于京东商城&#xff0c;主要模块有验证、用户、第三方登录、首页广告、商品、购物车、订单、支付以及后台管理系统。 项目开发模式采用前后端不分离的模式&#xff0c;为了提高搜索引擎排名&#xff0c;页面整体刷新采用jinja2模板引擎实现&#xff0c;…

mysql解压缩 1067_windows安装mysql8.0.0解压版附出现1067错误解决方法

1、自己到mysql官网下载mysql-8.0.0-dmr-winx64.zip解压缩安装包2、下载页面地址&#xff1a;https://dev.mysql.com/downloads/mysql/3、解压缩到任意目录(我自己是D:\DevTools\mysql-8.0.0)4、配置环境变量添加path路径为你的mysql8.0.0路径下面的bin目录(我的目录是D:\DevTo…

基于C语言的函数指针应用-消息命令处理框架

简述大家都知道&#xff0c;在C语音中指针的地位很重要&#xff0c;各种指针&#xff0c;功能很强大&#xff01;但是用不好&#xff0c;指针也比较容易出问题。这里介绍的是函数指针的一种应用方法&#xff0c;即使用函数指针来实现消息命令的注册与回调处理。代码测试的处理函…

框架中建立浮动框架_建立代理,而不是框架

框架中建立浮动框架自从引入Java注释以来&#xff0c;它已成为大型应用程序框架API的组成部分。 此类API的很好示例是Spring或Hibernate的示例&#xff0c;其中添加了几行注释代码可实现非常复杂的程序逻辑。 尽管人们可以争论这些特定API的缺点&#xff0c;但大多数开发人员都…

easyexcel 动态列_easyexcel动态表头列导出SequenceDiagram 阅读源码事半功倍

EasyExcel简介Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题&#xff0c;但POI还是有一些缺陷&#xff0c;比如07版Excel解压缩以及解压后存储都是…

python3进阶_Python3 进阶教程 2020全新版

REVENGE_7771天前如果不创建class类的话&#xff0c;直接使用dog.name是会报错的&#xff0c;因为一般数据类型不接受这种调用方式0赞 0采集潘某人永不屈服2天前class Student()定义的时候&#xff0c;需要在括号内写明继承的类Person在__init__()方法&#xff0c;需要调用sup…

C语言中的输入输出

在C语言中提供了许多内置的输入输出函数。标准文件的定义在C语言中会把所有设备当文件来处理。为了访问键盘和屏幕&#xff0c;以下三个文件会在程序执行时而打开。标准文件文件指针设备标准输入stdin键盘标准输出stdout屏幕标准错误stderr屏幕C 语言中的输入/输出通常使用内置…

sqlalchemy与mysql区别_sqlite3和sqlalchemy有什么区别?

sqlite3是一个嵌入式RDBMS。A relational database management system (RDBMS) is a database management system (DBMS) that is based on the relational model as introduced by E. F. Codd. Most popular commercial and open source databases currently in use are based…

lambda 延迟执行_Java Lambdas和低延迟

lambda 延迟执行总览 有关在Java和低延迟中使用Lambda的主要问题是&#xff1a; 他们会产生垃圾吗&#xff0c;您能做些什么吗&#xff1f; 背景 我正在开发一个支持不同有线协议的库。 这个想法是&#xff0c;您可以描述要写入/读取的数据&#xff0c;并且有线协议确定它是否…

C语言“悬空指针”和“野指针”究竟是什么意思?

各位&#xff0c;提起C语言我们很自然就会想到指针二字&#xff0c;没错&#xff0c;作为C的核心和灵魂&#xff0c;它的地位咱们就不再赘述了&#xff0c;今天我们想跟大家讲的是指针中的两个特有名词&#xff1a;“悬空指针”和“野指针”。悬空指针C语言中的指针可以指向一块…

grad在python什么模块_深度学习(Deep Learning)基础概念1:神经网络基础介绍及一层神经网络的python实现...

此专栏文章随时更新编辑&#xff0c;如果你看到的文章还没写完&#xff0c;那么多半是作者正在更新或者上一次没有更新完&#xff0c;请耐心等待&#xff0c;正常的频率是每天更新一篇文章。 该文章是“深度学习&#xff08;Deep Learning&#xff09;”系列文章的第一部分&…

ubuntu终端命令停止_从命令行关闭Linux计算机的5种方法

没有操作系统是完美的。 即使相对稳定,驱动程序和应用程序也可能存在问题。 Linux也不例外。 尽管比Windows更稳定(在许多情况下,并非全部!),但可能还需要重新启动Linux计算机。 这可能是因为某些东西不起作用。 或者,您可能通过SSH连接到远程计算机或服务器,并希望它重新…

C语言编写简单朗读发音小工具!!

各位&#xff0c;今天给大家带来C语言结合VBS脚本写的一个简单的朗读小工具&#xff0c;做一个能够发音的C语言程序&#xff08;保证简单&#xff0c;人人都能学会&#xff09;。具备的知识体系&#xff1a;C语言基本框架C语言输入输出C语言文件操作C语言system函数VBS指令&…

jgit_JGit身份验证说明

jgitJGit中的身份验证与本地Git大致相同。 支持SSH和HTTP&#xff08;S&#xff09;等常用协议及其身份验证方法。 本文总结了如何使用JGit身份验证API安全地访问远程Git存储库。 尽管本文中的示例使用CloneCommand&#xff0c;但是可以将所描述的技术应用于连接到远程存储库的…

未发现oracle(tm)客户端和网络组件_SpringColud Eureka的服务注册与发现

一、Eureka简介本文中所有代码都会上传到git上&#xff0c;请放心浏览 项目git地址&#xff1a;https://github.com/839022478/Spring-Cloud在传统应用中&#xff0c;组件之间的调用&#xff0c;通过有规范的约束的接口来实现&#xff0c;从而实现不同模块间良好的协作。但是被…

mysql global index_Oracle中addsplit partition对globallocal index的影响

生产库中某些大表的分区异常&#xff0c;需要对现有表进行在线操作&#xff0c;以添加丢失分区&#xff0c;因为是生产库&#xff0c;还是谨慎点好&#xff0c;今天有空&#xff0c;针对addspli生产库中某些大表的分区异常&#xff0c;需要对现有表进行在线操作&#xff0c;以添…