【问题标题】:OneToMany always is fetched even i use LazyLoad即使我使用 LazyLoad,OneToMany 也总是被获取
【发布时间】:2019-10-17 22:27:57
【问题描述】:

我有一个简单的问题,我不确定为什么这不起作用,我希望有人解释一下我在对用户进行查询时总是获取角色以及为什么我总是获取角色。

基本上我创建了 User 类并添加了 LazyLoaded 角色列表,但是当我执行查询时,我总是得到角色,这是我不想做的事情。有人可以解释一下为什么会这样吗?

基本上我想要实现的是在我想要的时候获取角色,我的理解是,当我在查询中使用带有 LazyLoad 的 LEFT JOIN FETCH 时,应该获取所有角色...

下面我添加了所有获取角色列表的类和查询,即使我没有在查询中使用 LEFT JOIN FETCH..

我有一个简单的用户类,如下所示:

@Entity
@Table(name = "users")
data class User (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        var id: Long?,

        var sponsorId: Long,

        var firstName: String,

        var lastName: String,

        var photo: String,

        @Column(nullable = false, unique = true)
        var username: String,

        @JsonIgnore
        var password: String,

        @JsonIgnore
        var enabled: Boolean
) {
        @OneToMany(mappedBy = "userId", fetch = FetchType.LAZY)
        var roles: Set<UserRole> = emptySet()
}

我还有第二个简单的类:

@Entity
@Table(name = "user_role")
data class UserRole (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        var id: Long?,

        @JsonIgnore
        var userId: Long?,

        @Enumerated(EnumType.STRING)
        var role: Role
)

在我的存储库中,我有这个查询,如您所见,我没有加入 FETCHED 角色,但无论如何我得到了用户列表和角色列表......

@Repository
interface UserRepository : JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.sponsorId = :sponsorId")
    fun findAllBySponsorId(@Param("sponsorId") sponsorId: Long): Set<User>

}

【问题讨论】:

  • 你认为它为什么会被获取?即使你调用 user.getRoles() 进行延迟加载,你仍然会得到它们。
  • 嗯,我没有在任何地方明确调用 user.getRoles(),我唯一调用的是那个查询 (findAllBySponsorId)
  • 也许你正在序列化为 JSON,然后编组库自己调用所有的 getter。
  • 有办法检查吗?我在返回用户列表的端点上调用此查询

标签: hibernate spring-boot jpa spring-data-jpa spring-data


【解决方案1】:

杰克逊可能是这里的罪魁祸首,对我来说也是如此。

您需要让 Jackson 知道您正在使用 Hibernate。

将此添加到您的 pom 中,以便它可以正确处理延迟加载:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

并为其创建一个 Bean,例如将其添加到您的应用程序类中:

@Bean
public Module hibernate5Module() {
    return new Hibernate5Module();
}

【讨论】:

  • 是的,很可能是这样。但部分题外话,也许只是个人喜好:不要这样做。创建一个单独的类以用于外部通信(DTO)。如果这看起来像是一种负担,您可以使用 Lombok 和 MapStruct 之类的东西。除非它是一个 POC/家庭项目,您只是用来自学,否则为一个好的可扩展项目架构付出的代价并不大。
  • 您的评论听起来很有趣,能否提供简单的代码示例?
【解决方案2】:

延迟初始化有效,但由于spring.jpa.open-in-view=true (spring default),在将对象序列化为JSON 时会获取您的集合。

长话短说:即使在视图层中,您也有与当前线程绑定的休眠会话。更多here

我建议设置spring.jpa.open-in-view=false,这会使事情更明确并且性能更好。

如果您只读取数据,我建议您使用投影Spring docs。术语 CQRS 也会对您有所帮助。

【讨论】:

    猜你喜欢
    • 2019-11-18
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 2021-01-01
    • 2022-11-10
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多