惠州酒店网站建设,网站建设有哪些主题,餐饮营销网站建设,清河企业做网站介绍 休眠获取策略确实可以使几乎没有爬网的应用程序和响应速度很快的应用程序有所不同。 在这篇文章中#xff0c;我将解释为什么您应该选择基于查询的获取而不是全局获取计划。 取得101 Hibernate定义了四种关联检索策略 #xff1a; 提取策略 描述 加入 原始SELECT语… 介绍 休眠获取策略确实可以使几乎没有爬网的应用程序和响应速度很快的应用程序有所不同。 在这篇文章中我将解释为什么您应该选择基于查询的获取而不是全局获取计划。 取得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查询变量的行为。 我将重用我先前在获取策略文章中介绍的实体模型 产品实体具有以下关联 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 SetImage images new LinkedHashSetImage(); 公司协会被标记为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_idcompany1_.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();
CriteriaQueryProduct cq cb.createQuery(Product.class);
RootProduct 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越多对我们应用程序性能的影响就越大。 休眠标准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_idhibernatea2_.id
where this_.id?][1]} 此查询使用连接抓取策略而不是选择抓取通过JPQL / HQL和标准的API使用。 休眠条件和多个EAGER集合 让我们看看将图像收集获取策略设置为EAGER时会发生什么 OneToMany(fetch FetchType.EAGER, cascade CascadeType.ALL, mappedBy product, orphanRemoval true)
OrderBy(index)
private SetImage images new LinkedHashSetImage(); 将生成以下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_idhibernatea2_.id
left outer join Image images3_ on this_.idimages3_.product_id
where this_.id?
order by images3_.index][1]} 休眠条件不会自动将父实体列表分组。 由于存在一对多子表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实体引用它们均指向同一一级缓存条目。 要解决此问题我们需要指示休眠标准使用不同的根实体 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