我正在使用 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 秒。
我相信由于延遲加載,這種情況正在發生。優化它的最佳方法是什么?一種選擇是進行分頁,但我不能這樣做。我需要所有結果。
有什么辦法可以并行執行嗎?我嘗試呼叫 parellelStream() 而不是 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 秒),然后處理速度更快。無論哪種方式,它都是相似的時間。
為了加快流程,有沒有辦法并行執行流代碼塊并將所有結果收集到串列中?
uj5u.com熱心網友回復:
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.util.Date 過濾與特定國家/地區的關系。
所以Step1優化:
如果您想過濾與來自特定國家/地區的用戶關聯的產品,那么這可以在 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。
Step2優化:
除了上述之外,您不僅可以通過將資料庫查詢移動到 JPA 層來傳遞資料庫查詢中的 java 過濾,還可以通過在 JPA 中定義要加載關聯的查詢來進一步優化查詢,Owner以便它當您創建 DTO 時,以后不會點擊資料庫來檢索它。您可以使用 實作此目的join fetch,因此您的查詢現在應變為:
@Query("SELECT p FROM Product p JOIN FETCH p.owner own where p.owner IS NOT NULL AND own.userGroup IS NOT NULL AND own.country IS NOT NULL AND own.country.id = :countryId")
List<Product> findProductRelatedWithUserFromCountry(@Param String countryId);
Step3優化:
如果我們想更進一步,似乎大多數時候使用 DTO 投影會加快執行速度。這可能會發生,因為查詢將只定義它需要檢索和轉換為 DTO 而不是完整物體的特定資訊。
所以你現在的查詢是:
@Query("SELECT new org.your.package.where.dto.is.ProductDTO(p.id.productNbr, p.price, own.name) FROM Product p JOIN FETCH p.owner own where p.owner IS NOT NULL AND own.userGroup IS NOT NULL AND own.country IS NOT NULL AND own.country.id = :countryId")
List<ProductDTO> findProductRelatedWithUserFromCountry(@Param String countryId);
還要記住在您的ProductDTO.class.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/513446.html
上一篇:SpringbootJPA多對多查詢|查找參加過的學生的所有課程課程
下一篇:JavaspringhibernateJPA@ManyToAllfindAll()在大資料上速度很慢,創建了許多子查詢
