我试图使用实体图来避免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 ;
答案 0 :(得分:1)
将EntityGraphType.FETCH
更改为EntityGraphType.LOAD
public interface SysPermRepository extends JpaRepository<SysPerm, Long>{
@EntityGraph(value = "test", type = EntityGraphType.LOAD)
List<SysPerm> findByPval(String pval);
}
我的问题已通过这种方式解决,您可以尝试一下。
答案 1 :(得分:0)
我遇到了同样的问题,并在这篇文章中解决了有关使用JPA查询RDBMS上存储的分层数据的替代方法:
https://jivimberg.io/blog/2018/08/04/recursive-queries-on-rdbms-with-jpa/
这说明了如何创建和使用NamedEntityGraphs。
部分代码:
@Entity
@NamedEntityGraphs(
NamedEntityGraph(name = "womanWithDaughters",
attributeNodes = [NamedAttributeNode(value = "daughters", subgraph = "daughterWithDaughters")],
subgraphs = [
NamedSubgraph(
name = "daughterWithDaughters",
attributeNodes = [NamedAttributeNode("daughters")]
)
]
)
)
data class Woman (
fun findWomanUsingEntityGraph(id: Long): Woman {
val graph = em.createEntityGraph(Woman::class.java)
.also { it.addSubgraph<Woman>("daughters") }
return em.find(Woman::class.java, id, mapOf("javax.persistence.loadgraph" to graph))
}