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不起作用

left outer join的on不起作用

ORACLE:使用 LEFT JOIN 时物化视图不起作用

SQL,未使用的 LEFT JOIN 速度变慢,优化器不起作用?

JPA Left Join IS NULL条件不起作用

Hibernate中left join fetch 查询出现重复的对象