如何在Spring Controller中获取FetchType.LAZY与JPA和Hibernate的关联

2022-08-31 07:00:53

我有一个 Person 类:

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Role> roles;
    // etc
}

具有懒惰的多对多关系。

在我的控制器中,我有

@Controller
@RequestMapping("/person")
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/get")
    public @ResponseBody Person getPerson() {
        Person person = personRepository.findOne(1L);
        return person;
    }
}

而PersonRepository就是这个代码,根据本指南编写

public interface PersonRepository extends JpaRepository<Person, Long> {
}

但是,在这个控制器中,我实际上需要懒惰数据。如何触发其加载?

尝试访问它将失败

未能懒惰地初始化角色集合:no.dusken.momus.model.Person.roles,无法初始化代理 - 无会话

或其他例外情况,具体取决于我尝试的内容。

我的xml描述,以防万一。

谢谢。


答案 1

您必须对惰性集合进行显式调用才能对其进行初始化(通常的做法是为此目的进行调用)。在Hibernate中,有一个专用的方法(),但JPA没有等效的方法。当然,当会话仍然可用时,您必须确保调用已完成,因此请使用 注释控制器方法。另一种方法是在控制器和存储库之间创建一个中间服务层,该层可以公开初始化惰性集合的方法。.size()Hibernate.initialize()@Transactional

更新:

请注意,上述解决方案很简单,但会导致对数据库的两个不同的查询(一个针对用户,另一个针对其角色)。如果你想获得更好的性能,请将以下方法添加到你的Spring Data JPA存储库接口:

public interface PersonRepository extends JpaRepository<Person, Long> {

    @Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)")
    public Person findByIdAndFetchRolesEagerly(@Param("id") Long id);

}

此方法将使用 JPQL 的 fetch join 子句在到数据库的单个往返行程中热切地加载角色关联,从而减轻上述解决方案中两个不同查询所产生的性能损失。


答案 2

虽然这是一篇旧文章,但请考虑使用@NamedEntityGraph(Javax Persistence)和@EntityGraph(Spring Data JPA)。该组合有效。

@Entity
@Table(name = "Employee", schema = "dbo", catalog = "ARCHO")
@NamedEntityGraph(name = "employeeAuthorities",
            attributeNodes = @NamedAttributeNode("employeeGroups"))
public class EmployeeEntity implements Serializable, UserDetails {
// your props
}

然后是弹簧回购,如下所示

@RepositoryRestResource(collectionResourceRel = "Employee", path = "Employee")
public interface IEmployeeRepository extends PagingAndSortingRepository<EmployeeEntity, String>           {

    @EntityGraph(value = "employeeAuthorities", type = EntityGraphType.LOAD)
    EmployeeEntity getByUsername(String userName);

}

推荐