Java JPA Hibernate惰性获取属性和一个查询
考虑以下实体:Java JPA Hibernate惰性获取属性和一个查询,java,performance,hibernate,jpa,spring-data-jpa,Java,Performance,Hibernate,Jpa,Spring Data Jpa,考虑以下实体: 用户实体: 用户实体的角色应以惰性方式获取。问题是,当使用角色时(调用getter),hibernate会通过查询每个角色以及查询每个角色的每个权限来获取角色,从而导致n+1问题 因此,我的问题是:如何通过一个查询惰性地获取用户角色?我能否以某种方式利用RoleEntity的EntityGraph? 注意:我已尝试使用@Fetch: @Fetch(FetchMode.JOIN) @ManyToMany(fetch = FetchType.LAZY) @JoinTable(na
用户实体:
用户实体
的角色
应以惰性方式获取。问题是,当使用角色时(调用getter),hibernate会通过查询每个角色以及查询每个角色的每个权限来获取角色,从而导致n+1问题
因此,我的问题是:如何通过一个查询惰性地获取用户角色?我能否以某种方式利用RoleEntity
的EntityGraph?
注意:我已尝试使用@Fetch
:
@Fetch(FetchMode.JOIN)
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "role_permission", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "permission_id", referencedColumnName = "id"))
private List<PermissionEntity> permissions = new ArrayList<>();
不过,我对这个解决方案不满意。为什么我需要添加@BatchSize
?我认为使用子图可能会对您有所帮助。看看他的网站上的描述:,引用:
指定@Fetch(FetchMode.JOIN)
将导致即时抓取(忽略FetchType.LAZY
)
但是,@Fetch(FetchMode.JOIN)
(使用时请注意)
我猜您使用的是查询,因此@Fetch
被忽略了
@BatchSize
只影响延迟加载的集合,然后一次加载多个集合
例如,假设一个用户具有多个角色,每个角色都与多个权限关联,访问第一个角色的权限也会在同一查询中加载更多角色的权限
因此,当使用@BatchSize
时,在访问用户所有角色的所有权限时,您仍应至少看到2个选择(第一个用于角色,第二个用于不同角色的权限)
另见:
为了能够仅为特定用例急切地获取用户的所有关联角色和权限,您可以选择使用@EntityGraph
,例如,在这样的自定义存储库查询中:
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
@EntityGraph(attributePaths = { "roles", "roles.permissions" })
Optional<UserEntity> findWithPermissionsById(Long id);
}
@存储库
公共接口用户存储库扩展了JpaRepository{
@EntityGraph(AttributePath={“角色”,“角色.权限”})
可选findWithPermissionsById(长id);
}
这样,只有一条连接所有所需实体的大型select语句才能获取具有所有角色和所有权限的用户。
(为了避免混淆:find和ById之间的方法名中间部分是任意的,因此它也可以是findFooById
。
使用带有子图的@NamedEntityGraph
也可以获得类似的行为
@Entity(name = "permission")
public class PermissionEntity {
@Id
@Column(name = "id", columnDefinition = "serial")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
}
@Fetch(FetchMode.JOIN)
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "role_permission", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "permission_id", referencedColumnName = "id"))
private List<PermissionEntity> permissions = new ArrayList<>();
@Fetch(FetchMode.JOIN)
@BatchSize(size = 1000)
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "role_permission", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "permission_id", referencedColumnName = "id"))
private List<PermissionEntity> permissions = new ArrayList<>();
@NamedEntityGraph(
name = "graph.AuthorBooksPublisherEmployee",
attributeNodes = @NamedAttributeNode(value = "books", subgraph = "subgraph.book"),
subgraphs = {
@NamedSubgraph(name = "subgraph.book",
attributeNodes = @NamedAttributeNode(value = "publisher", subgraph = "subgraph.publisher")),
@NamedSubgraph(name = "subgraph.publisher",
attributeNodes = @NamedAttributeNode(value = "employees")) })
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
@EntityGraph(attributePaths = { "roles", "roles.permissions" })
Optional<UserEntity> findWithPermissionsById(Long id);
}