网站热度查询,夸克网站免费进入,保定建设局网站,网站定位与建设介绍 诸如JPA的ORM框架通过帮助我们在对象-关系数据映射期间避免了很多样板代码#xff0c;从而简化了我们的开发过程。 但是#xff0c;它们还会给表带来一些其他问题#xff0c;N 1是其中之一。 在本文中#xff0c;我们将简短地探讨该问题以及避免这些问题的一… 介绍 诸如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 ListPurchaseOrderItem 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秒 。 端点正在根据某些条件获取单个实体对于我们当前的示例该实体将遵循以下原则 TypedQueryPurchaseOrder 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是结果中唯一用于后续计算的数据。 有几个客户有超过一千个订单。 每个命令依次又有数千个其他几种不同类型的子级。 不用说每当在此端点接收到针对这些订单的请求时数据库中就会执行数千个查询。 为了提高性能我所做的就是- TypedQueryString 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);
ListPurchaseOrderDTO 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