【问题标题】:Converting list of model entities with relationships to DTO takes time将具有关系的模型实体列表转换为 DTO 需要时间
【发布时间】:2022-09-30 19:51:03
【问题描述】:

我正在使用 Spring Boot JPA 来获取对象列表(现在使用 Java 8)。每个对象都有关系,我也使用相关对象转换为 dto 列表。 假设我有以下模型类。

public class Product {

    @EmbeddedId
    private ProductId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = \"userid\", referencedColumnName = \"USER_ID\")
    @MapsId(\"userId\")
    private User owner;
}

public class User {

    @Id
    @Column(name = \"USER_ID\")
    private Long userId;
    
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = \"gp_code\", referencedColumnName = \"GP_CODE\")
    @JoinColumn(name = \"userid\", referencedColumnName = \"USER_ID\")
    private UserGroup userGroup;
    
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
            @JoinColumnOrFormula(formula = @JoinFormula(value = \"country_id\", referencedColumnName = \"COUNTRY_ID\")),
            @JoinColumnOrFormula(column = @JoinColumn(name = \"region_code\", referencedColumnName = \"REGION_CODE\")) })
    private Country country;
}

我查询List<Product> 并使用流将其转换为 dto 对象。在此期间,我调用相关实体来获取数据。我有下面的代码并且工作正常,除非列表太多。如果列表中有 1000 多个项目,则大约需要 30 秒。

我相信由于延迟加载,这种情况正在发生。优化它的最佳方法是什么? 一种选择是进行分页,但我不能这样做。我需要所有结果。

有没有办法并行执行这个?我尝试调用并行 Stream() 而不是 stream(),但结果相同。

public List<ProductDTO> getProducts(String countryId) {
    //List<Product> products = Query Result
    List<ProductDTO> productsList = products.stream().filter(isOwnerFromCountryAndInAnyGroup(countryId))
                    .map(product -> getProductDTO(product)).collect(Collectors.toList());
}

private Predicate<? super Product> isOwnerFromCountryAndInAnyGroup(String countryId) {
        return product -> {
            User user = product.getOwner();
            return null != user && null != user.getCountry()
                    && user.getCountry().getCountryId().equals(countryId) && (null != user.getUserGroup());
        };
    }
    
private ProductDTO getProductDTO(Product product) {
        ProductDTO productDTO = new ProductDTO();
        productDTO.setProductNbr(product.getId().getProductNbr());
        productDTO.setPrice(product.getPrice());
        productDTO.setOwnerName(product.getOwner().getName());
        return productDTO;
    }

编辑

为了在这里提问,我错过了添加productDTO.setOwnerName(product.getOwner().getName()); 行。通过查询或使用过滤器,我得到了正确数量的结果。并且通过延迟加载,查询返回更快,然后在为每一行调用 getOwner() 时,该过程需要时间(30 秒)。 使用 FethType.EAGER,查询需要相似的时间(30 秒),然后处理速度更快。无论哪种方式,它都是相似的时间。

为了加快流程,有没有办法并行执行流代码块并将所有结果收集到列表中?

  • 与我们分享查询,我相信应该有问题
  • 只是一个建议 - 通常我们使用 fetch type lazy - 当我们有 ManyToOne 映射时 - 以节省检索时间并仅在需要时加载。对于 OneToOne 和 ManyToOne - 使用 fetch 类型急切不会是一项昂贵的操作
  • @PanagiotisBougioukos 它是通过查询找到的。查询响应更快。
  • @AshishShetkar 谢谢。我想我可以做出改变并尝试
  • 你能分享一下什么类型的findBy吗?

标签: java java-stream


【解决方案1】:
public List<ProductDTO> getProducts(String countryId) {
    //List<Product> products = Query Result
    List<ProductDTO> productsList = products.stream().filter(isOwnerFromCountryAndInAnyGroup(countryId))
                    .map(product -> getProductDTO(product)).collect(Collectors.toList());
}

从这里的用例来看,我非常有信心创建 DTO 并不需要时间。是你从数据库中检索一个庞大的集合(甚至是完整的产品表)然后您仅从 java 过滤与特定国家/地区的关系。

如果您想过滤与来自特定国家/地区的用户相关联的产品,那么这可以在 JPA 级别进行,并在数据库中以最佳方式进行翻译。然后资源(内存,cpu)的分配会更加优化,而不是你的java应用程序试图加载一个巨大的数据集并在那里过滤它。

尝试:

@Query("SELECT p FROM Product p where p.owner IS NOT NULL AND p.owner.userGroup IS NOT NULL AND p.owner.country IS NOT NULL AND p.owner.country.id = :countryId")
List<Product> findProductRelatedWithUserFromCountry(@Param String countryId); 

并从您的方法getProducts 中删除过滤。

【讨论】:

  • 我已经更新了这个问题。请检查编辑部分。在转换为 DTO 时,我正在调用 owner 方法,因此需要时间。有没有办法并行处理该块?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
  • 2016-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多