@ElementCollection 的 JPA 延迟加载

Posted

技术标签:

【中文标题】@ElementCollection 的 JPA 延迟加载【英文标题】:JPA lazy loading of @ElementCollection 【发布时间】:2021-02-04 05:14:26 【问题描述】:

在阅读了几个网页后,我仍然不明白为什么我的@ElementCollection 会急切地加载。我的理解是,任何 @ElementCollection 都应始终默认延迟加载。如您所见,情况并非如此 - 您将在本文末尾看到控制台输出。我尝试使用 @ElementCollection(fetch = FetchType.LAZY) 注释强制延迟加载,但这并没有改变任何东西。有人可以解释并说明如何更改注释以延迟加载吗?

我有一个 JavaFX 应用程序。因此,我必须使用 Properties 和 AccessType.PROPERTY。改变这不是一种选择。此外,我正在使用:Java 11、Hibernate 5.4.15.Final、mysql 8、Spring boot 2.2.7

这是实体类的摘录

@Entity
@DiscriminatorValue(Term.PRODUCT)
@Access(AccessType.PROPERTY)    
public class Product extends Term 
    ...
    protected ListProperty<Double> marketSize;
    protected ListProperty<Double> marketGrowth;
    protected ListProperty<Integer> marketUnits;
    ...
    public Product() 
        ...
        marketSize = new SimpleListProperty<>();
        marketGrowth = new SimpleListProperty<>();
        marketUnits = new SimpleListProperty<>();
        ...
    

    @ElementCollection(fetch = FetchType.LAZY)
    public List<Double> getMarketSize() 
        return marketSize;
    


    public void setMarketSize(List<Double> marketSize) 
        this.marketSize = new SimpleListProperty<Double>(FXCollections.observableArrayList(marketSize));
    

    public ListProperty<Double> marketSizeProperty() 
        return marketSize;
    

    // Likewise for marketGrowth and marketUnits

    ...

相关服务类

@Service
public class TermService 

    ...

    public ObservableList<Product> getAllProducts() 
        ObservableList<Product> products = FXCollections.observableArrayList();
        products.addAll(productRepository.findAll());
    
        return products;
    

相关的存储库类

@Repository
public interface ProductRepository extends TermRepository<Product> 


 @NoRepositoryBean`
        public interface TermRepository<T extends Term> extends JpaRepository<T, Long> 
        
            List<T> findByIdentifier(String indentifier);
            List<T> findByGoal(String goal);
            List<Product> findByParent(Term parent);
            List<T> findAll();
            T getById(Long id);
        

当我的业务逻辑从 TermService 调用 getAllProducts() 时,结果如下(摘录)

DEBUG 09:01 o.h.e.j.s.SqlStatementLogger.logStatement:128: select term0_.id as id2_66_1_, term0_.goal as goal3_66_1_, term0_.identifier as identifi4_66_1_, term0_.level as level5_66_1_, term0_.parent_id as parent_46_66_1_, term0_.plannedBegin as plannedb6_66_1_, term0_.plannedEnd as plannede7_66_1_, term0_.state as state8_66_1_, term0_.fk_successor as fk_succ47_66_1_, term0_.fk_testplan as fk_test48_66_1_, term0_.timeUnit as timeunit9_66_1_, term0_.type as type10_66_1_, term0_.version as version11_66_1_, term0_.affection as affecti12_66_1_, term0_.classification as classif13_66_1_, term0_.classificationJustification as classif14_66_1_, term0_.customerCharacteristics as custome15_66_1_, term0_.customerDenomination as custome16_66_1_, term0_.devMaterialCosts as devmate17_66_1_, term0_.directive as directi18_66_1_, term0_.factoryCosts as factory19_66_1_, term0_.fixedCosts as fixedco20_66_1_, term0_.generalAdminCosts as general21_66_1_, term0_.iec60601 as iec22_66_1_, term0_.iec62304 as iec23_66_1_, term0_.iec62366 as iec24_66_1_, term0_.intendedUse as intende25_66_1_, term0_.iso13485 as iso26_66_1_, term0_.iso14155 as iso27_66_1_, term0_.iso14971 as iso28_66_1_, term0_.leasingCosts as leasing29_66_1_, term0_.manufacturingCosts as manufac30_66_1_, term0_.marketGeography as marketg31_66_1_, term0_.marketValueSegment as marketv32_66_1_, term0_.negativeImpact as negativ33_66_1_, term0_.prodMaterialCosts as prodmat34_66_1_, term0_.productLine_id as product49_66_1_, term0_.fk_prodowner as fk_prod50_66_1_, term0_.fk_prjmanager as fk_prjm51_66_1_, term0_.projectedSalesPrice as project35_66_1_, term0_.purpose as purpose36_66_1_, term0_.reach as reach37_66_1_, term0_.fk_regmanager as fk_regm52_66_1_, term0_.restriction as restric38_66_1_, term0_.rohs as rohs39_66_1_, term0_.salaryCosts as salaryc40_66_1_, term0_.salesAdminCosts as salesad41_66_1_, term0_.systemDescription as systemd42_66_1_, term0_.fk_sysengineer as fk_syse53_66_1_, term0_.technologyReadinessLevel as technol43_66_1_, term0_.unlike as unlike44_66_1_, term0_.varCosts as varcost45_66_1_, term0_.term_level as term_lev1_66_1_, term1_.id as id2_66_0_, term1_.goal as goal3_66_0_, term1_.identifier as identifi4_66_0_, term1_.level as level5_66_0_, term1_.parent_id as parent_46_66_0_, term1_.plannedBegin as plannedb6_66_0_, term1_.plannedEnd as plannede7_66_0_, term1_.state as state8_66_0_, term1_.fk_successor as fk_succ47_66_0_, term1_.fk_testplan as fk_test48_66_0_, term1_.timeUnit as timeunit9_66_0_, term1_.type as type10_66_0_, term1_.version as version11_66_0_, term1_.affection as affecti12_66_0_, term1_.classification as classif13_66_0_, term1_.classificationJustification as classif14_66_0_, term1_.customerCharacteristics as custome15_66_0_, term1_.customerDenomination as custome16_66_0_, term1_.devMaterialCosts as devmate17_66_0_, term1_.directive as directi18_66_0_, term1_.factoryCosts as factory19_66_0_, term1_.fixedCosts as fixedco20_66_0_, term1_.generalAdminCosts as general21_66_0_, term1_.iec60601 as iec22_66_0_, term1_.iec62304 as iec23_66_0_, term1_.iec62366 as iec24_66_0_, term1_.intendedUse as intende25_66_0_, term1_.iso13485 as iso26_66_0_, term1_.iso14155 as iso27_66_0_, term1_.iso14971 as iso28_66_0_, term1_.leasingCosts as leasing29_66_0_, term1_.manufacturingCosts as manufac30_66_0_, term1_.marketGeography as marketg31_66_0_, term1_.marketValueSegment as marketv32_66_0_, term1_.negativeImpact as negativ33_66_0_, term1_.prodMaterialCosts as prodmat34_66_0_, term1_.productLine_id as product49_66_0_, term1_.fk_prodowner as fk_prod50_66_0_, term1_.fk_prjmanager as fk_prjm51_66_0_, term1_.projectedSalesPrice as project35_66_0_, term1_.purpose as purpose36_66_0_, term1_.reach as reach37_66_0_, term1_.fk_regmanager as fk_regm52_66_0_, term1_.restriction as restric38_66_0_, term1_.rohs as rohs39_66_0_, term1_.salaryCosts as salaryc40_66_0_, term1_.salesAdminCosts as salesad41_66_0_, term1_.systemDescription as systemd42_66_0_, term1_.fk_sysengineer as fk_syse53_66_0_, term1_.technologyReadinessLevel as technol43_66_0_, term1_.unlike as unlike44_66_0_, term1_.varCosts as varcost45_66_0_, term1_.term_level as term_lev1_66_0_ from Term term0_ left outer join Term term1_ on term0_.id=term1_.fk_successor where term0_.fk_successor=? 
DEBUG 09:01 o.h.e.j.s.SqlStatementLogger.logStatement:128: select marketgrow0_.Product_id as product_1_29_0_, marketgrow0_.marketGrowth as marketgr2_29_0_ from Product_marketGrowth marketgrow0_ where marketgrow0_.Product_id=? 
DEBUG 09:01 o.h.e.j.s.SqlStatementLogger.logStatement:128: select marketsize0_.Product_id as product_1_31_0_, marketsize0_.marketSize as marketsi2_31_0_ from Product_marketSize marketsize0_ where marketsize0_.Product_id=? 
DEBUG 09:01 o.h.e.j.s.SqlStatementLogger.logStatement:128: select marketunit0_.Product_id as product_1_33_0_, marketunit0_.marketUnits as marketun2_33_0_ from Product_marketUnits marketunit0_ where marketunit0_.Product_id=? 

我希望只有第一行,而不是最后三行。

【问题讨论】:

您是否尝试在没有继承实体层次结构且仅使用来自java.util.* 的集合的纯休眠应用程序上重现您的问题? 不,还没有。我希望有人知道这个问题,或者至少可以解释这种行为。如果几天后不是这样,我可以从一个“干净”的 mock 开始,增加继承和集合的复杂性以尝试重现。 尝试在 getter 中设置断点。我敢打赌你会以某种方式访问​​导致延迟初始化的值。 你输了。我在发布问题之前尝试过,但忘了提及。无论如何,我只是再次尝试。调试器不会在三种方法中的任何一种中停止 【参考方案1】:

如果元素集合被注释(或 xml 映射)为 LAZY,除非有 EntityGraph 提示,否则不应加载它。尝试其他 JPA 提供程序,例如生成优化 SQL 的 cmobilecom-jpa。

【讨论】:

以上是关于@ElementCollection 的 JPA 延迟加载的主要内容,如果未能解决你的问题,请参考以下文章

JPA @ElementCollection 我该如何查询?

查询中的 JPA 基本类型 ElementCollection 计算值

JPA @ElementCollection 注释是不是总是产生一对多的关系?

JPA - 多对多作为 ElementCollection

查询@ElementCollection JPA

对 JP-QL (JPA 2.0) 中的“ElementCollection”映射字段执行“MEMBER OF”查询