问题描述
嗨,我尝试多线程处理我的函数,以执行不同条件的查询,但我认为 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 的解决方案持开放态度。如何正确获取数据?
解决方法
获取性能是一个困难的话题,我完全理解您不想在实体级别更改获取类型或模式。通常,这可以通过使用实体图来定义关联图来解决,以获取每个查询的关联图。在您的特定情况下,问题在于线程不会获取以后需要的所有状态。当您稍后在不同的线程中访问该状态时,代理不再引用持久性上下文(因为它绑定到事务/线程)并且因您看到的 LazyInitializationException 而失败。您可以通过使用实体图来解决这个问题,这样就不会发生延迟加载,或者通过启用 hibernate.enable_lazy_load_no_trans
属性来按需创建会话来获取数据,但我认为这是 @EntityView(TransSalesOrder.class)
public interface TransSalesOrderOnlyResponseDto {
@IdMapping
Long getId();
String getName();
List<TransDeliveryOrderDto> transDeliveryOrder;
@EntityView(TransDeliveryOrder.class)
interface TransDeliveryOrderDto {
@IdMapping
Long getId();
String getName();
}
}
的完美用例{3}}。
我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义的模型之间轻松映射,例如类固醇上的 Spring Data Projections。这个想法是,您可以按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
您的用例的 DTO 模型可能如下所示,其中包含 Blaze-Persistence Entity-Views:
TransSalesOrderOnlyResponseDto a = entityViewManager.find(entityManager,TransSalesOrderOnlyResponseDto.class,id);
查询是将实体视图应用于查询的问题,最简单的就是通过 id 查询。
Page<TransSalesOrderOnlyResponseDto> findAll(Pageable pageable);
Spring Data 集成允许您像使用 Spring Data Projections 一样使用它:Blaze-Persistence Entity Views
char local_7 [32];
long local_78;
printf("Give it a try");
gets(local_7);
if (local_78 != 0x4141414141414141) {
if (local_78 == 0x1122334455667788) {
puts ("That's won")
}
puts("Let's continue");
}
最好的部分是,它只会获取实际需要的状态!