公告:魔扣目录网为广大站长提供免费收录网站服务,提交前请做好本站友链:【 网站目录:https://www.morko.net 】, 免友链快审服务(50元/站),

点击这里在线咨询客服
新站提交
  • 网站:51998
  • 待审:31
  • 小程序:12
  • 文章:1030137
  • 会员:747

本文介绍了最佳做法是在添加到@ManyToMany的所有者端集合时避免选择所有行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当添加到表示@ManyToMany关联的所属方的集合时,我的JPA实现(Hibernate)将首先选择关联中的所有行,以确定该实体是否已经存在于集合中。

我了解这背后的机制,但在处理大型连接表时,这不是很好的性能。当我知道需要插入条目时,避免加载连接表的所有元素的最佳做法是什么?

我将以一个典型的用户/角色场景为例,为简洁起见,省略了getters/setters/初始化式:

@Entity
public class User {
    @Id
    private Long id;

    @ManyToMany
    private Set<Role> roles;
}

@Entity
public class Role {
    @Id
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "roles")
    private Set<User> users;
}

我让User成为拥有方,这样JPA将跟踪对User.Roles的更改。

以下代码导致该问题:

User user = em.find(User.class, 1L);
Role role = em.find(Role.class, 1L);

// This line causes the issue
user.getRoles().add(role);

em.persist(user);

当我添加到用户角色时,执行以下SELECT操作:

select
     roles0_.users_id as users_id1_20_0_,
     roles0_.roles_id as roles_id2_21_0_,
     role1_.id as id1_17_1_,
     role1_.name as name2_17_1_ 
from User_Role roles0_ 
inner join Role role1_ on roles0_.roles_id=role1_.id 
where roles0_.users_id=?

这对于较小的集合来说很好,但对于较大的集合就有问题。

我可以想到以下解决方案,我想知道我应该选择哪一个,或者是否有更好的方法来做到这一点?

1.执行本机查询:

INSERT INTO User_Role (users_id, roles_id) VALUES (1, 1)

2.为连接表创建实体:

@Entity
IdClass(UserRole.PK)
public class UserRole {
    @Id
    private User user;
    @Id
    private Role role;

    public static class PK {
        private User user;
        private Role role;
    }
}

然后我可以运行:

User user = em.find(User.class, 1L);
Role role = em.find(Role.class, 1L);
UserRole userRole = new UserRole(user, role);
em.persist(userRole);

我倾向于对INSERT使用原生查询,但我希望得到一些反馈,了解执行此操作的最‘JPA’方式是什么。

推荐答案

《使用Hibernate的Java持久性》一书(第298页)指出,多对多通常最好使用关联类(有点像您在第二个解决方案中已有的UserRole),然后为两端映射两个一对多关系–即每个用户有多个UserRole,每个角色有多个UserRole。这是最”JPA”的做事方式,我想你会得到你想要的表现。

现在细微之处:

    关联类应该有一个基于用户和角色的ID的组合键,而不是它自己的主键。本书给出了一个在Association类中创建一个@Embedble静态内部类的示例,该类包含两个主要类(在您的例子中是User和Role)的ID。这些ID到关联表中的列的映射是在这个内部类中完成的。
    在您向其传递特定角色和用户的关联类的构造函数中,您将填充内部类,然后将”this”(即您正在创建的关联实例)添加到传入的用户和角色的集合中(例如,role.getUserRoles().add(This))。
    删除关联时,必须同时从用户和角色中删除该关联。也就是说,在角色端,您将执行以下操作:role.getUserRoles().Remove(UserRole),然后您将在用户端执行相同的操作,然后删除关联:ession.ete(UserRole)。

如果您遵循这些步骤,Hibernate将知道正在发生的一切,并且您的缓存应该是好的。您还可以使用级联启用传递性持久性。

编辑:如上所述,这实际上并不会消除试图避免的查询。经过进一步思考,我没有一个可以消除查询的答案,但我可以指出为什么JPA的行为方式如您所见。在原始设置中,每一项都有其他内容的。由于集合是唯一的,并且JPA提供程序遵循集合语义,因此它们必须确保关系是唯一的。因此,如果您添加一个关系,它必须进行查询以确保该关系不存在。它可以只查询您试图添加的关系,也可以查询整个集合,然后检查内部。如果您要将多个内容添加到集合中,则后者是更好的方法,而这正是他们针对此进行优化的原因。JPA提供程序永远不会做的一件事是,如果您试图添加重复的关系,JPA提供程序永远不会依赖于底层数据库约束–JPA提供程序更喜欢在Java层处理Java约束

Hibernate还支持袋子选项,该选项允许重复,因此可以避免检查…但这样,您的数据库中就会有重复的关系。

这篇关于最佳做法是在添加到@ManyToMany的所有者端集合时避免选择所有行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,

分享到:
标签:ManyToMany 做法 所有者 是在 添加 选择 集合
用户无头像

网友整理

注册时间:

网站:5 个   小程序:0 个  文章:12 篇

  • 51998

    网站

  • 12

    小程序

  • 1030137

    文章

  • 747

    会员

赶快注册账号,推广您的网站吧!
最新入驻小程序

数独大挑战2018-06-03

数独一种数学游戏,玩家需要根据9

答题星2018-06-03

您可以通过答题星轻松地创建试卷

全阶人生考试2018-06-03

各种考试题,题库,初中,高中,大学四六

运动步数有氧达人2018-06-03

记录运动步数,积累氧气值。还可偷

每日养生app2018-06-03

每日养生,天天健康

体育训练成绩评定2018-06-03

通用课目体育训练成绩评定