java - Spring JPA Entity Graph 和 Self Reference 发生 N+1 查询

标签 java jpa entitygraph

我尝试使用实体图来避免N+1查询, 它按预期工作。
自引用实体有所不同,虽然这些代码可以得到正确的列表,但发生了N+1查询。

我的问题是如何消除带有自引用实体的N+1查询?

提前致谢。

日志和代码如下

Hibernate: 
    select
        sysperm0_.pval as pval1_0_0_,
        children1_.pval as pval1_0_1_,
        sysperm2_.pval as pval1_0_2_,
        sysperm0_.parent as parent4_0_0_,
        sysperm0_.created as created2_0_0_,
        sysperm0_.leaf as leaf3_0_0_,
        sysperm0_.pname as pname5_0_0_,
        sysperm0_.ptype as ptype6_0_0_,
        sysperm0_.updated as updated7_0_0_,
        children1_.parent as parent4_0_1_,
        children1_.created as created2_0_1_,
        children1_.leaf as leaf3_0_1_,
        children1_.pname as pname5_0_1_,
        children1_.ptype as ptype6_0_1_,
        children1_.updated as updated7_0_1_,
        children1_.parent as parent4_0_0__,
        children1_.pval as pval1_0_0__,
        sysperm2_.parent as parent4_0_2_,
        sysperm2_.created as created2_0_2_,
        sysperm2_.leaf as leaf3_0_2_,
        sysperm2_.pname as pname5_0_2_,
        sysperm2_.ptype as ptype6_0_2_,
        sysperm2_.updated as updated7_0_2_ 
    from
        sys_perm sysperm0_ 
    left outer join
        sys_perm children1_ 
            on sysperm0_.pval=children1_.parent 
    left outer join
        sys_perm sysperm2_ 
            on children1_.parent=sysperm2_.pval 
    where
        sysperm0_.pval=?


Hibernate: 
    select
        children0_.parent as parent4_0_0_,
        children0_.pval as pval1_0_0_,
        children0_.pval as pval1_0_1_,
        children0_.parent as parent4_0_1_,
        children0_.created as created2_0_1_,
        children0_.leaf as leaf3_0_1_,
        children0_.pname as pname5_0_1_,
        children0_.ptype as ptype6_0_1_,
        children0_.updated as updated7_0_1_ 
    from
        sys_perm children0_ 
    where
        children0_.parent=?

    .......XN

    492373 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    5197227 nanoseconds spent preparing 8 JDBC statements;
    18997333 nanoseconds spent executing 8 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

实体

@Table(name="sys_perm")
@Entity
@NamedEntityGraph(
    name = "test",
    attributeNodes = {
        @NamedAttributeNode(value="children",subgraph="sub_perm"),
    },
    subgraphs = {
        @NamedSubgraph(
            name = "sub_perm",
            attributeNodes = {
                @NamedAttributeNode("_parent")
        }
    )
  }
)
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class SysPerm implements Serializable {

    @Id
    private String pval;
    private String parent;
    private String pname;
    private Integer ptype;
    private Boolean leaf;
    @CreationTimestamp
    private Date created;
    @UpdateTimestamp
    private Date updated;

    @ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
    @JoinColumn(name = "parent", referencedColumnName = "pval", insertable=false, updatable=false)
    @JsonIgnore
    private SysPerm _parent;

    @OneToMany(mappedBy="_parent", fetch=FetchType.EAGER, cascade={CascadeType.ALL})
    private List<SysPerm> children = new ArrayList<>();
}

存储库

public interface SysPermRepository extends JpaRepository<SysPerm, Long>{
    @EntityGraph(value = "test", type = EntityGraphType.FETCH)
    List<SysPerm> findByPval(String pval);
}

架构

CREATE TABLE `sys_perm` (
  `pval` varchar(50) NOT NULL ,
  `parent` varchar(25) DEFAULT NULL ,
  `pname` varchar(50) DEFAULT NULL ,
  `ptype` int(3) DEFAULT NULL ,
  `leaf` tinyint(1) DEFAULT NULL ,
  `created` timestamp NULL DEFAULT NULL ,
  `updated` timestamp NULL DEFAULT NULL ,
  PRIMARY KEY (`pval`),
  UNIQUE KEY `pval` (`pval`),
  KEY `FKaiy87e3krvn4suwleaooces17` (`parent`),
  CONSTRAINT `FKaiy87e3krvn4suwleaooces17` FOREIGN KEY (`parent`) REFERENCES `sys_perm` (`pval`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

最佳答案

通过将 EntityGraphType.FETCH 更改为 EntityGraphType.LOAD 即可解决该问题

public interface SysPermRepository extends JpaRepository<SysPerm, Long>{
    @EntityGraph(value = "test", type = EntityGraphType.LOAD)
    List<SysPerm> findByPval(String pval);
}

我的问题已经按照这个方法解决了,你可以试试。

关于java - Spring JPA Entity Graph 和 Self Reference 发生 N+1 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55821659/

相关文章:

hibernate - 需要解释事先冲洗的必要性以避免在使用 Spring 进行测试时出现误报吗?

jpa - 自 Java 10.0 NullPointer 在搜索持久性时 - JPA eclipselink 2.6.5

java - JPA 实体图和分页

java - 如何在不定义@Entity 的情况下使用 EntityManager 将 db BLOB 列转换为 byte[]?

java - 如何限制 Hibernate 实体图中使用的列

java - JPA的实体图的FETCH和LOAD有什么区别?

java - 如何使用 JavaMail API 读取电子邮件附件(当 contentType 为 text/plain 时)

java - 检查 JTable 是否包含带标识符的列

java - org.apache.http 库缺少包

java - 多个数组元素的组合