Spring data JPA - 使用@EntityGraph 导致“指定的实体图不适用于实体”警告

Mic*_*mal 8 java hibernate spring-data-jpa spring-boot entitygraph

我将我的应用程序从 spring boot 2.2.5 升级到 2.3.3,并且我正在使用带有 5.4.20.Final 板载的 spring data JPA starter。我的实体在编译时得到增强。

现在,当我在覆盖方法上使用@EntityGraph带有attributePaths属性的注释时,我收到此警告:findAllJpaRepository

2020-08-19 12:13:41.121  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : Entity graph specified is not applicable to the entity [DictionaryLang(id=1601, name=null, lang=null)]. Ignored.
2020-08-19 12:13:41.483  WARN 9348 --- [nio-8060-exec-3] [] [] o.h.engine.internal.TwoPhaseLoad         : Entity graph specified is not applicable to the entity [DictionaryValueLang(id=3051, lang=null, name=null)]. Ignored.
Run Code Online (Sandbox Code Playgroud)

即使此警告 - 图形已正确获取 - 我只能在日志中看到一个 SQL 查询,并且应用程序的行为与更新前一样。

这是我的存储库代码:

public interface DictionaryRepository extends JpaRepository<Dictionary, Long>, QuerydslPredicateExecutor<Dictionary> {

    @EntityGraph(attributePaths = {"langs", "values", "values.langs"})
    @Override
    Page<Dictionary> findAll(Predicate predicate, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

这是我的实体:

@Entity
@Table(name = "DICTIONARIES")
public class Dictionary {

    @Id
    @SequenceGenerator(name = "SEQ_DICTIONARIES", sequenceName = "SEQ_DICTIONARIES")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_DICTIONARIES")
    private Long id;

    @OrderBy("ordinal ASC")
    @OneToMany(mappedBy = "dictionary", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<DictionaryValue> values;

    @OneToMany(mappedBy = "dictionary", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<DictionaryLang> langs;

}


@Entity
@Table(name = "DICTIONARY_LANGS")
public class DictionaryLang extends BaseEntity {

    @Id
    @SequenceGenerator(name = "SEQ_DICTIONARY_LANGS", sequenceName = "SEQ_DICTIONARY_LANGS")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_DICTIONARY_LANGS")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @LazyToOne(LazyToOneOption.PROXY)
    @JoinColumn(name = "DICTIONARY_ID")
    private Dictionary dictionary;

}
Run Code Online (Sandbox Code Playgroud)

如何解决这个警告?我可以看到这个警告发生在 hibernateTwoPhaseLoad类的那些行中:

GraphImplementor fetchGraphContext = session.getFetchGraphLoadContext();
if ( fetchGraphContext != null && !fetchGraphContext.appliesTo( entity.getClass() ) ) {
    LOG.warnf( "Entity graph specified is not applicable to the entity [%s]. Ignored.", entity);
    fetchGraphContext = null;
    session.setFetchGraphLoadContext( null );
}
Run Code Online (Sandbox Code Playgroud)

yar*_*hyn 7

这是因为在 spring 2.3.3 中将 hibernate 更新到 5.4.20。

如果你降级hibernate tp 5.4.18这个问题就会消失,升级到5.4.21也没有用。

在我的例子中,hibernate 不仅仅是添加一条警告消息,它实际上会忽略 @EntityGraph(attributePaths = {...}) 注释并根据映射执行查询生成,在我的情况下,这会导致 N+1 个问题和数千个查询。 此外,EntityGraph.EntityGraphType.LOAD 并没有解决问题,因为在这种情况下,hibernate 将根据映射获取类型加载 @EntityGraph 中未提及的所有映射,如果您获取大集合,这可能会增加很多查询。

查看关于EntityGraphType 的详细信息

o 降级休眠,您可以使用

 implementation ("org.springframework.boot:spring-boot-starter-data-jpa") {
     // to remove fibernate that came with new spring
     exclude group: "org.hibernate", module: "hibernate-core" 
 }
 // to add old hibernate 
 implementation "org.hibernate:hibernate-core:5.4.18.Final"
Run Code Online (Sandbox Code Playgroud)

这是 hibernate 中的一个相关问题是https://hibernate.atlassian.net/browse/HHH-14124 它说受影响的版本 4.5.19 和修复版本是 4.5.20。但是,我在 spring 2.3.3(hibernate 4.5.20) 中遇到错误

更新:这是针对此错误发布的问题。它已经修复:https : //hibernate.atlassian.net/browse/HHH-14212

  • 实际上,我所有的关系都被指定为 LAZY,因此使用“EntityGraphType.LOAD”并不是什么大问题,但感谢您指出这一点。我宁愿降级整个 ​​spring data JPA - 我不确定新版本的 spring data 不会与旧的 hibernate 冲突。 (2认同)