由于在关联的集合上使用fetch = FetchType.LAZY,遇到了问题,例如“org.hibernate.LazyInitializationException:无法初始化角色的集合:代理初始化失败-没有会话”。
现在将fetch = FetchType.LAZY更改为fetch = FetchType.EGAR是最糟糕的解决方案,因为它会引起其他问题。
然后我想,如果有一种方法可以在运行时将fetch类型从lazy更改为egar以进行某些操作……
然后我尝试理解问题,例如为什么我遇到了LazyInitializationException。
所以我意识到,这个问题发生是因为我们在关闭会话后执行数据库操作,因此我们必须在会话内进行所有数据库操作。
因此,解决方案是将在其中执行数据库操作的方法包装在
事务中。请检查下面的代码片段->
@Transactional
public void fetchThroughLazy() {
List<UserEntity> userList = aeqplUserRepository.findByEmailEndingWith("@amazon.com");
userList.forEach(user->{
logger.info("user --->{}",user);
logger.info("user permission--->{}",user.getPermissions());
});
}
但是这并不是一个好的解决方案,因为它会导致Hibernate N+1问题。
最佳方案---> 使用EntityGraph或Join Fetch
请查看下面的代码片段 --->>
public void fetchThroughJPQLJoinFetch() {
List<UserEntity> userList = entityManager.createQuery("select distinct u from UserEntity u left join fetch u.permissions Where u.email like :endsWith",UserEntity.class)
.setParameter("endsWith", "%@google.com")
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
userList.forEach(user->{
logger.info("user --->{}",user);
logger.info("user permission--->{}",user.getPermissions());
});
}
public void fetchThroughJPQLEntityGraph() {
EntityGraph<UserEntity> userEntityGraph = em.createEntityGraph(UserEntity.class);
userEntityGraph.addSubgraph("permissions");
List<UserEntity> userList = em.createQuery("Select u From UserEntity u Where u.email Like :endsWith",UserEntity.class)
.setParameter("endsWith", "%@facebook.com")
.setHint(QueryHints.LOADGRAPH, userEntityGraph)
.getResultList();
userList.forEach(user->{
logger.info("user --->{}",user);
logger.info("user permission--->{}",user.getPermissions());
});
}
@Entity
@Table(name="user")
public class UserEntity {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "email")
private String email;
@OneToMany(mappedBy="userEntity",cascade = CascadeType.All,fetch= FetchType.LAZY)
private List<PermissionEntity> cmList =new ArrayList<>();
}
@Entity
@Table(name="permission")
public class PermissionEntity {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "type")
private String type;
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name = "user_id")
private UserEntity userEntity;
}
Note-> 避免使用Join Fetch超过一次,否则会引发MultipleBagFetchException异常。