Java 带有连接、逻辑和性能查询的ORM(使用JPA和Spring)

Java 带有连接、逻辑和性能查询的ORM(使用JPA和Spring),java,database,spring,jpa,orm,Java,Database,Spring,Jpa,Orm,我有三个表:组、用户和组成员。groups表绑定到一个Group类,具有User类和Group_成员的用户用于建模它们之间的多对多关系 下面是小组成员的样子 id | user_id | group_id ---+---------+--------- 现在让我们假设我想向一个组添加一个成员,知道组id和用户id。我有两种方法:要么使用组id获取组,要么更新他的成员列表并保存组,要么创建一个直接更新组成员的SQL请求。在这里,第二种方法似乎不那么耗时,但我必须编写一个特定的SQL请求,而使用第

我有三个表:组、用户和组成员。groups表绑定到一个Group类,具有User类和Group_成员的用户用于建模它们之间的多对多关系

下面是小组成员的样子

id | user_id | group_id
---+---------+---------
现在让我们假设我想向一个组添加一个成员,知道组id和用户id。我有两种方法:要么使用组id获取组,要么更新他的成员列表并保存组,要么创建一个直接更新组成员的SQL请求。在这里,第二种方法似乎不那么耗时,但我必须编写一个特定的SQL请求,而使用第一种方法,我可以让JPA完成这项工作

我的问题是:使用第一种或第二种方法更相关吗?为什么?是否有一种方法可以让JPA完成这项工作,而不执行比第二种解决方案更多的请求


谢谢。

我认为“第一种方法”的问题在于,如果一个组有10000名成员,那么您可能(无意中)拉住所有人,只是为了添加一个额外的成员

但是,假设一个成员平均不属于超过4-5个组,则反向听起来更有效(获取该成员并将其他组添加到其列表中)


当然,使用“第二种方法”,您可以通过一次插入创建关联,但如果我们假设用户数量很大,组数量相对较少,那么首先就无法实现使用ORM的全部目的,然后,通过反转逻辑并将组添加到用户中,可以实现相对较好的效率:

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue
    private long id;

    @Column(unique = true)
    private String username;

    @ManyToMany
    private Set<Group> groups = new HashSet<>();
    ...
@实体
@表(name=“users”)
公共类用户{
@身份证
@生成值
私人长id;
@列(唯一=真)
私有字符串用户名;
@许多
私有集组=新HashSet();
...
组集默认为延迟加载。实际上,这意味着一旦您尝试读取或写入select语句,它就会被加载

请注意,对应的组实体没有使用“Set members”建模的匹配关系。您不希望将组与其10000个用户一起加载,以便再添加一个用户

如果这还不够好,您可以将联接表建模为一个实体,但在本例中,这可能会带来更多麻烦

下面是Hibernate在我描述的场景中发出的一些示例查询:

    TypedQuery<Group> gq = em.createQuery("select g from Group g where g.name='two'", Group.class);
    Group g = gq.getSingleResult();
    TypedQuery<User> uq = em.createQuery("select u from User u where u.username='u1' ", User.class);
    User u = uq.getSingleResult();

Hibernate: select group0_.id as id1_0_, group0_.name as name2_0_ from groups group0_ where group0_.name='two'
Hibernate: select user0_.id as id1_1_, user0_.username as username2_1_ from users user0_ where user0_.username='u1'

    u.getGroups().add(g);

Hibernate: select groups0_.users_id as users_id1_1_0_, groups0_.groups_id as groups_i2_2_0_, group1_.id as id1_0_1_, group1_.name as name2_0_1_ from users_groups groups0_ inner join groups group1_ on groups0_.groups_id=group1_.id where groups0_.users_id=?
Hibernate: insert into users_groups (users_id, groups_id) values (?, ?)
TypedQuery gq=em.createQuery(“从g组中选择g,其中g.name='two',Group.class”);
g组=gq.getSingleResult();
TypedQuery uq=em.createQuery(“从用户u中选择u,其中u.username='u1',User.class”);
用户u=uq.getSingleResult();
休眠:从group0中选择group0\u0.id作为id1\u0\u0,group0\u0.name作为name2\u0\u0,其中group0\u0.name='two'
Hibernate:从users user0\uwhere user0\u0.username='u1'中选择user0\u1.id作为id1\u1,user0\u1.username作为username2\u1
u、 getGroups().add(g);
休眠:选择groups0.users.id作为users\u id1\u 0\u,groups0.groups\u id作为groups\u i2\u 0\u,group1.id作为id1\u 0\u 1\u,group1\u.name作为name2\u 0\u 1\u来自用户组groups0\u内部连接组group1\u在groups0\u.groups\u id=group1\u id其中groups0.users\u id=?
Hibernate:在用户组(用户id、组id)中插入值(?,)

我认为对于这个特定的用例来说,这是一个非常合理的策略,因为您不会让很多用户同时执行这些操作,而且单个额外的查询不会导致任何性能问题。

我同意您的看法,但是如果ORM逻辑大大改变了性能,那么保留它不是很愚蠢吗没有一种方法可以同时利用ORM和性能吗?当然,在我的存储库类中,我经常自动连接EntityManager和JdbcOperations。不过,必须小心事务管理。你是对的,但这是假设你不将集合绑定到组实体。假设你想轻松获得gro的成员up:您只是移动了问题,因为您将被迫手动创建SQL查询。我认为这是Hibernate中缺少的一个功能,可以非常简单地处理。这实际上取决于用户数等。但这是一个非常简单的查询:TypedQuery uq=em.createQuery(“从用户u中选择u,其中:g u.groups的成员”,User.class);我还要补充一点,您正在讨论编写SQL来维护联接表是否是一个好主意。如果您这样做,那么您的不同更新范例可能会在某个时候影响您。在这种情况下,坚持纯JPA有助于将风险降至最低。这是我们通常将联接表映射到ac的原因之一实际实体,而不是让jpa将
manytomy
映射到您的联接表。它允许您根据用户和组的ID,并使用EntityManager的
persist()
方法,自己创建一个
GroupMember
实体。如果您不确定我的意思,我可以在回答中加以说明。