【问题标题】:How to avoid unnecessary queries when adding an entry to a ManyToMany collection in JPA?向 JPA 中的 ManyToMany 集合添加条目时如何避免不必要的查询?
【发布时间】:2021-09-10 18:48:47
【问题描述】:

我有以下两个通过多对多关系链接的实体

data class GroupEntity(
    @Id
    val id: String,
    val name: String
) {
    @ManyToMany
    val users: MutableSet<UserEntity> = HashSet()
}

@Entity
data class UserEntity(
    @Id
    val id: UUID,
    val name: String,

    @ElementCollection
    val interests: Set<InterestEmbeddable> = HashSet(),

    @ElementCollection
    val badges: Set<BadgeEmbeddable> = HashSet()
) {
    @ManyToMany(mappedBy = "users")
    val groups: MutableSet<GroupEntity> = HashSet()
}

每个实体都有一个对应的JpaRepository。 每当我尝试将user 添加到group 时,hibernate 都会在后台对数据库进行许多查询。它实际上从group 的每个user 中加载每个interestsbadges 我正在尝试将我的user 添加到。

var group = this.groupRepository.getById(groupId);
var user = this.userRepository.getById(userId);

group.getUsers().add(user);
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?
Hibernate: select interests0_.user_entity_id as user_en1_47_0_, interests0_.name as name2_47_0_, interests0_.value as value3_47_0_ from user_entity_interests interests0_ where interests0_.user_entity_id=?
Hibernate: select badges0_.user_entity_id as user_en1_46_0_, badges0_.badge_id as badge_2_46_0_ from user_entity_badges badges0_ where badges0_.user_entity_id=?

您可以想象这会导致我出现性能问题。顺便说一下,我在尝试删除用户时遇到了同样的问题。

如何避免这些额外的查询?

我一直在阅读Best pratice to avoid selecting all rows when adding to owning side collection of a @ManyToMany,但我对那里提供的答案并不满意。如果可能,我想避免将连接表具体化为实体。

【问题讨论】:

  • 我不希望发生这种情况。首先,您能否澄清一下您是否有任何相等或哈希码的实现——通过 lombok 或其他方式——可能会引用所有字段?
  • 我正在使用 Kotlin 数据类,所以我正在使用它提供的 equals / hashcode。这意味着不考虑组和用户可变集,因为它们在正文中声明。
  • @AlanHay 好的,我想我从你的回答中知道了。事实上,我的其他 2 个集合是 equals / hashcode 的一部分,这使得休眠加载集合。通过将它们移出等号/哈希码,我不再获得多个查询。

标签: hibernate jpa spring-data-jpa many-to-many


【解决方案1】:

@AlanHay 的评论将我引向了解决方案:我将我的 interestsbadges 集合作为我的 equals / hashcode 的一部分,因此在这样做时它触发了所有元素的加载。

【讨论】:

    猜你喜欢
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多