我遇到了一个问题,我在JPA中有一个查询。因为我有一些集合,所以我需要使用左连接获取或内部连接获取
我的问题是使用setFirstResult
和setMaxResult
,以便带回准确的结果数。每次我看到整个结果都带回来,并且只有在使用maxResult之后。
有什么办法可以使maxResult之前吗?
非常感谢 !
这是更多信息:
我的问题是当我使用它时:
startIndex = 0;
maxResults = 10;
query.setFirstResult(startIndex);
query.setMaxResults(maxResults);
我在日志中看到此消息:
2011年6月7日09:52:37
org.hibernate.hql.ast.QueryTranslatorImpl列表注意:用集合访存指定的firstResult /
maxResults;申请内存!
我看到200结果返回(在日志中),在HashSet中之后,我终于得到了10个结果。
在内存中似乎恢复了200结果,并在内存中应用了maxResults之后。
我正在搜索是否有任何方法可以获取和限制结果数。
我使用了一种解决方法,我使用maxResult进行了第一个查询,以询问订单ID,但未进行任何提取。一切正常,它使用了极限指令。在对提取使用“大”查询并将结果限制在id列表内之后,请带回第一个查询。
这是我的完整查询,没有我的解决方法(请注意,@Bozho的讲话没有限制):
select o from Order o
left join fetch o.notes note
left join fetch o.orderedBy orderedBy
left join fetch orderedBy.address addressOrdered
left join fetch orderedBy.language orderedByLg
left join fetch orderedByLg.translations orderedByLgTtrad
left join fetch o.deliveredTo deliveredTo
left join fetch deliveredTo.address addressDelivered
left join fetch deliveredTo.language deliveredToLg
left join fetch deliveredToLg.translations
left join fetch o.finalReceiptPlace finalReceiptPlace
left join fetch finalReceiptPlace.address addressFinalReceiptPlace
left join fetch finalReceiptPlace.language finalReceiptPlaceLg
left join fetch finalReceiptPlaceLg.translations
inner join fetch o.deliveryRoute delivery
left join fetch delivery.translations
inner join fetch o.type orderType
left join fetch orderType.translations
inner join fetch o.currency currency
left join fetch currency.translations
left join fetch o.attachments
left join fetch note.origin orig
left join fetch orig.translations
left join fetch o.supplier sup
left join fetch sup.department dep
left join fetch o.stateDetail stateD
inner join fetch stateD.state stat
where 1=1 and o.entryDate >= :startDat
TL; DR
Hibernate不知道它需要获取指定数量的Order对象的扁平化联合查询的多少行,因此它必须将整个查询加载到内存中。请参阅下面的说明。
要了解为什么Hibernate这样做,您需要了解Hibernate如何处理JPA实体所涉及的ORM(对象关系映射)。
为您的订单考虑一套简化的实体。类Order
包含2个字段:number
和customerId
和订单行列表。类OrderLine
包含productCode
和quantity
字段,以及uid
对父Order
的键和引用。
这些类可以这样定义:
@Entity
@Table(name = "ORDER")
public class Order {
@ID
@Column(name = "NUMBER")
private Integer number;
@Column(name = "CUSTOMER_ID")
private Integer customerId;
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
@OrderBy
private List<OrderLine> orderLineList;
.... // Rest of the class
}
@Entity
@Table(name = "ORDER_LINE")
public class OrderLine
{
@ID
@Column(name = "UID")
private Integer uid;
@Column(name = "PRODUCT_CODE")
private Integer productCode;
@Column(name = "QUANTITY")
private Integer quantity;
@Column(name = "ORDER_NUMBER")
private Integer orderNumber;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "ORDER_NUMBER", referencedColumnName = "NUMBER", insertable = false, updatable = false)
private Order order;
.... // Rest of the class
}
现在,如果您对这些实体执行了以下JPQL查询:
SELECT o FROM Order o LEFT JOIN FETCH o.orderLineList
然后Hibernate将该查询作为类似于以下内容的“扁平化” SQL查询执行:
SELECT o.number, o.customer_id, ol.uid, ol.product_code, ol.quantity, ol.order_number
FROM order o LEFT JOIN order_line ol ON order_line.order_number = order.number
这将产生如下结果:
| o.number | o.customer_id | ol.uid | ol.product_code | ol.quantity |
|==========|===============|========|=================|=============|
| 1 | 123 | 1 | 1111 | 5 |
| 1 | 123 | 2 | 1112 | 6 |
| 1 | 123 | 3 | 1113 | 1 |
| 2 | 123 | 4 | 1111 | 2 |
| 2 | 123 | 5 | 1112 | 7 |
| 3 | 123 | 6 | 1111 | 6 |
| 3 | 123 | 7 | 1112 | 5 |
| 3 | 123 | 8 | 1113 | 3 |
| 3 | 123 | 9 | 1114 | 2 |
| 3 | 123 | 10 | 1115 | 9 |
...etc
Hibernate将使用它来“重建” Order
带有附加OrderLine
子对象列表的对象。
但是,由于每个订单的订单行数是随机的,因此Hibernate无法知道要获得指定的Order
所需最大对象数需要多少行查询。因此,必须丢弃整个结果查询并在内存中建立对象,直到其数量正确为止,然后再丢弃其余结果集。它产生的日志警告暗示了这一点:
ATTENTION: firstResult/maxResults specified with collection fetch; applying in memory!
现在,我们只是发现这些查询会对服务器内存使用产生重大影响,并且在尝试执行这些查询时,我们的服务器发生了内存不足错误而出现故障。
顺便说一句,我现在要说的是,这大部分只是我的理论,我不知道实际的Hibernate代码是如何工作的。当让Hibernate记录它生成的SQL语句时,您可以从日志中收集大多数信息。
更新: 最近我发现了上面的一点“陷阱”。
考虑调用的第三个实体Shipment
,该实体用于订单的一个或多个行。
该Shipment
实体将@ManyToOne
与该实体有关联Order
。
假设您有2条相同订单的货件,其中有4行。
如果执行JPQL查询以下内容:
SELECT s FROM Shipment s LEFT JOIN s.order o LEFT JOIN FETCH o.orderLineList
您可能希望(或者至少是我这样做)取回2个装运对象,每个对象都引用同一个Order对象,该对象本身将包含4行。
不,又错了!实际上,您将获得2个Shipment对象,每个对象都引用相同的Order对象,其中包含 8
行!是的,订单中的行重复!是的,即使您指定了DISTINCT子句也是如此。
如果您在SO或其他地方(最著名的是Hibernate论坛)研究此问题,那么根据Hibernate的强大功能,您会发现它实际上是一个 功能,
而不是错误。有些人实际上 想要 这种行为!
去搞清楚。
问题内容: 我在服务器日志 “用集合获取指定的firstResult / maxResults;在内存中应用!”中 收到警告 。 。但是,一切正常。但我不要这个警告。 我的代码是 我的查询是 问题答案: 该警告的原因是,当使用访存联接时,结果集中的顺序仅由所选实体的ID定义(而不是由访存的联接定义)。 如果内存中的这种排序引起问题,请不要在JOIN FETCH中使用firsResult / max
问题内容: 我在服务器日志 “用集合获取指定的firstResult / maxResults;在内存中应用!”中 收到警告 。 。但是,一切正常。但我不要这个警告。 我的代码是 我的查询是 问题答案: 该警告的原因是,当使用访存联接时,结果集中的顺序仅由所选实体的ID定义(而不是由访存的联接定义)。 如果内存中的这种排序引起问题,请不要在JOIN FETCH中使用firsResult / max
我在服务器日志中收到一个警告“firstResult/max结果指定集合获取;在内存中应用!”。然而一切正常。但我不想要这个警告。
4.7. 申请内存 在Go语言中,大部分的类型都是值变量。例如int或struct(结构体)或array(数组)类型变量, 赋值的时候都是复制整个元素。如果需要为一个值类型的变量分配空间,可以用new(): type T struct { a, b int } var t *T = new(T); 或者更简洁的写法: t := new(
本文向大家介绍Android 程序申请权限注意事项,包括了Android 程序申请权限注意事项的使用技巧和注意事项,需要的朋友参考一下 为Android 程序申请权限注意 Android系统提供为程序提供了权限申请,即在manifest中使用uses-permission来申请即可.实现起来非常简单,但是有些问题会随之浮出水面. 常见的现象是,有时候新加一个权限,(在Google Play上)程序
使用Python3的函数注释,可以指定同构列表(或其他集合)中包含的项的类型,以便在PyCharm和其他IDE中进行类型暗示? int列表的伪python代码示例: 我知道使用Docstring是可能的... ... 但如果可能的话,我更喜欢注释样式。