LEFT JOIN FETCH 不起作用 - Spring 数据 JPA
Posted
技术标签:
【中文标题】LEFT JOIN FETCH 不起作用 - Spring 数据 JPA【英文标题】:LEFT JOIN FETCH not working - Spring data JPA 【发布时间】:2021-09-11 21:46:40 【问题描述】:我在使用 LEFT JOIN FETCH 时遇到问题。请参考我下面的实体和存储库。
考虑一个场景,选修课程在任何时候都不会从表格中删除。但是可以删除学生信息。 数据库中的两个表之间没有主键和外键关系。只是我们有共同的列“STUDENT_ID”。
@NamedEntityGraphs(
@NamedEntityGraph(
name = "Student.optionalCourse",
attributeNodes = @NamedAttributeNode("optionalCourse")
)
)
@Table("STUDENT")
class Student
@Id
@column_name(STUDENT_ID)
private integer studentId;
@column_name(STUDENT_AGE)
private int studentAge;
@OneToMany(fetch = FetchType.LAZY, mappedBy="student")
private List<OptionalCourse> optionalCourse;
@NamedEntityGraphs(
@NamedEntityGraph(
name = "OptionalCourse.student",
attributeNodes = @NamedAttributeNode("student")
)
)
@Table("OPTIONAL_COURSES")
class OptionalCourse
@Id
@column_name(ID)
private Integer id;
@column_name(STUDENT_ID)
private Integer studentId;
@column_name(SUBJECT_NAME)
private String subjectName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "STUDENT_ID" , referencedColumnName="STUDENT_ID", insertable = false, updatable = false )
private Student student;
@Repository
@Transactional(rollbackFor = Exception.class)
public interface OptionalCourseRepository extends JpaRepository<OptionalCourse,Integer>
@Query(value = "SELECT oc FROM OptionalCourse oc LEFT JOIN FETCH oc.student where oc.studentId > :studentId",
countQuery = "SELECT count(oc.id) FROM OptionalCourse oc where oc.studentId > :studentId")
public Page<OptionalCourse> findOptionalSubjectPagesByStudentId(@Param("studentId") Integer studentId, Pageable pageable);
没有事务的服务方法:
public List<CustomBeanClass> retrieveRpdLogRequestsList(Integer studentId, Integer pageIndex, Integer pageResultsSize)
Pageable pageWithIndexAndSize = Pageable.unpaged();
if(Objects.nonNull(pageIndex) && Objects.nonNull(pageResultsSize) && pageIndex >= 0 && pageResultsSize > 0)
pageWithIndexAndSize = PageRequest.of(pageIndex, pageResultsSize);
Page<OptionalCourse> pageData = optionalCourseRepository.findOptionalSubjectPagesByStudentId(studentId, pageWithIndexAndSize);
List<OptionalCourse> pageDataList = pageData.toList();
pageDataList.forEach(course ->
OptionalCourse oc = course;
//When trying to fetch student info from optional course, when student info is not there then we are getting below error
oc.getStudent(); **//com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method hibernate & org.hibernate.LazyInitializationException: could not initialize proxy [com.xxx.xxx.Student#550] - no Session**
);
事务性的服务方法:
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public List<CustomBeanClass> retrieveRpdLogRequestsList(Integer studentId, Integer pageIndex, Integer pageResultsSize)
Pageable pageWithIndexAndSize = Pageable.unpaged();
if(Objects.nonNull(pageIndex) && Objects.nonNull(pageResultsSize) && pageIndex >= 0 && pageResultsSize > 0)
pageWithIndexAndSize = PageRequest.of(pageIndex, pageResultsSize);
Page<OptionalCourse> pageData = optionalCourseRepository.findOptionalSubjectPagesByStudentId(studentId, pageWithIndexAndSize);
List<OptionalCourse> pageDataList = pageData.toList();
pageDataList.forEach(course ->
OptionalCourse oc = course;
//When trying to fetch student info from optional course, when student info is not there then we are getting below error
oc.getStudent(); **// EntityNotFoundException - Its trying to fetch the dependent entity student here**
);
即使我使用了 LEFT JOIN FETCH,为什么当我调用依赖实体(即)oc.getStudent();生成的查询具有正确的语法为 LEFT OUTER JOIN,在 SQLDeveloper 中它给出了预期的结果。我们正在使用 Oracle 数据库。
我犯了什么错误?我不被允许使用 EAGER FETCH 策略。请通过 Lazy Fetch 本身帮助解决此问题。提前谢谢!!!!
【问题讨论】:
有人可以帮忙解决上述问题吗!!! 【参考方案1】:我猜你正在使用在 Spring 中默认启用的 OSIV(视图中打开会话)反模式?这是该方法的常见问题。问题是您的第一级缓存(持久性上下文)包含具有学生字段未初始化代理的实体。现在,即使您再次选择该实体并加入 fetch 关联,Hibernate 也不会替换该对象,因为它必须保留对象身份并且也不会替换代理。要解决这个问题,您必须在使用 EntityManager.clear()
进行查询之前清除持久性上下文
【讨论】:
在我们的项目中,我们只保留了 spring.jpa.open-in-view=false。 在进行查询之前您是否尝试运行EntityManager.clear()
?
会尽力让您知道。谢谢!!以上是关于LEFT JOIN FETCH 不起作用 - Spring 数据 JPA的主要内容,如果未能解决你的问题,请参考以下文章
具有分页的Spring-Data FETCH JOIN不起作用