【发布时间】:2021-04-28 14:57:52
【问题描述】:
您好,我尝试对执行具有不同条件的查询的函数进行多线程处理,但我认为 JPA 在我执行此操作时丢失了它的持久性包,因为数据不会显示并且出现错误。我将首先从我的同步代码开始,因为它工作,我将展示我的异步代码不工作。
这是我的实体类:
TransSalesOrder 类
@OneToMany(mappedBy = "transSalesOrder")
private List<TransDeliveryOrder> transDeliveryOrder;
TransDeliveryOrder 类
@OneToMany(mappedBy = "deliveryOrder", orphanRemoval = true, cascade = CascadeType.ALL)
private List<TransDeliveryOrderDetail> transDeliveryOrderDetail;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "transSalesOrderId")
private TransSalesOrder transSalesOrder;
这里是 TransDeliveryOrderDetail 类:
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "delivery_order_id", referencedColumnName = "id")
private TransDeliveryOrder deliveryOrder;
这是我的同步工作方式: 这是我的功能,执行其他 3 个功能:
public List<TransSalesOrderOnlyResponseDto> findUnAssignedSO() {
List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = findSOHaveItemLeftOverOnly();
transSalesOrdersResponseNew.addAll(findPureUnAssignedSO());
transSalesOrdersResponseNew.addAll(findSalesOrderWithBpsjInDeliveryOrder());
return transSalesOrdersResponseNew;
}
这是执行的 3 个函数:
private List<TransSalesOrderOnlyResponseDto> findSOHaveItemLeftOverOnly() {
List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSOHaveLeftOverButDone();
return buildTransSalesOrdersResponseNew(transSalesOrders);
}
private List<TransSalesOrderOnlyResponseDto> findPureUnAssignedSO() {
return iSalesOrderMapper.entityToSOOnlyDto(iTransSalesOrderQdslRepository.findUnAssignedSalesOrder());
}
private List<TransSalesOrderOnlyResponseDto> findSalesOrderWithBpsjInDeliveryOrder() {
List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSalesOrderWithBpsjInDeliveryOrder();
return buildTransSalesOrdersBpsjOnlyResponseNew(transSalesOrders);
}
这种方式是可行的,但后来我尝试异步我的 3 个方法,因为我的 3 个函数可以以异步方式执行,它们不必互相等待完成
这是我使用 CompletableFuture 的异步方式:
public List<TransSalesOrderOnlyResponseDto> findUnAssignedSO() {
List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = new ArrayList<>();
findSOHaveItemLeftOverOnly()
.thenAccept( transSalesOrdersResponseNew::addAll )
.thenCompose( v -> findPureUnAssignedSO() )
.thenAccept( transSalesOrdersResponseNew::addAll )
.thenCompose( v -> findSalesOrderWithBpsjInDeliveryOrder() )
.thenAccept( transSalesOrdersResponseNew::addAll )
.join();
return transSalesOrdersResponseNew;
}
private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findSOHaveItemLeftOverOnly() {
return CompletableFuture.supplyAsync(() -> {
List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSOHaveLeftOverButDone();
return buildTransSalesOrdersResponseNew(transSalesOrders);
});
}
private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findPureUnAssignedSO() {
return CompletableFuture.supplyAsync(() -> iSalesOrderMapper.entityToSOOnlyDto(iTransSalesOrderQdslRepository.findUnAssignedSalesOrder()));
}
private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findSalesOrderWithBpsjInDeliveryOrder() {
return CompletableFuture.supplyAsync(() -> {
List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSalesOrderWithBpsjInDeliveryOrder();
return buildTransSalesOrdersBpsjOnlyResponseNew(transSalesOrders);
});
}
当我运行我的 findUnAssignedSO 函数时,我得到了这个错误:
org.hibernate.LazyInitializationException: 延迟初始化失败 角色集合: com.bit.microservices.b2b.warehouse.entity.TransSalesOrder.transSalesOrderDetail, 无法初始化代理 - 没有会话
当我调试它时,我发现子数据没有加载,这是我尝试的选项:
- 我尝试使用 @Transactional 保持 JPA 附加,但它不起作用。
- 我不想更改与 EAGER 相关的 @OneToMany 中的 fetchType,我在互联网上阅读了以后会出现性能问题的所有内容
- 使用 Set insted of List,这也会导致性能问题
我没有显示我的存储库,因为我使用了混合的 JpaRepository 和 QueryDSL,但我对任何不需要附加到 QueryDSL 的解决方案持开放态度。如何正确获取数据?
【问题讨论】:
-
您应该检查所有内容是否在同一个线程中运行。会话不是线程安全的,并且在被不同线程使用时可能会出现奇怪的行为。另外,为什么要使用
CompletableFuture?在这种特殊情况下,我认为您不会从中获得任何好处。 -
错误究竟来自哪里?当您访问惰性(未获取)关系时,您已经知道对象与您正在读取它们的上下文分离,因为您已经关闭了用于读取它们的异步线程/上下文,所以我不太清楚您是什么寻找。您必须在上下文关闭之前预取所需的数据,或者在使用数据的进程中同步运行提取,以便上下文可以保持打开状态。至于“急切”地获取 1:M 关系的效率——这是许多解决方案的一个单独问题。
-
请参阅baeldung.com/hibernate-fetchmode 以修复您的集合映射,以便您可以让它们保持惰性(或急切)并且在获取时不让它加入主表 - 您目前已经导致 N* 查询作为您的方法遍历返回的数据并触及惰性关系。如果您想让模型关系保持惰性,只需让您的异步方法在返回之前触摸它们,或者使用图形/提示强制 JPA 在上下文关闭并返回数据之前为您获取它们。关键是在需要之前知道自己需要什么。
-
@Davide 哦,我想在单独的线程中执行 3 个数据库查询,所以他们不必互相等待完成,因为每个查询都会得到数千条记录,我想改进使用 CompletableFuture 的性能,有没有更好的方法来做到这一点?
-
@Chris 正如我所提到的,我不想更改 fetchType,因为 fetchMode 会覆盖 fetchType,它会影响我的其他功能性能
标签: java hibernate jpa spring-data-jpa completable-future