单向关联和双向关联有什么区别?
由于数据库中生成的表都是相同的,所以我发现的唯一区别是双向关联的每一侧都会有一个引用,而单向则没有。
这是一个单向关联
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
}
双向关联
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
@OneToMany(mappedBy="group")
private List<User> users;
}
区别在于组是否持有用户的引用。
所以我想知道这是否是唯一的区别?推荐哪个?
主要区别在于双向关系提供了双向导航访问,因此您无需显式查询即可访问另一侧。它还允许您将级联选项应用于两个方向。
请注意,导航访问并不总是好的,尤其是对于“一对多”和“多对多”的关系。想象一个包含数千个 User
的 Group
:
您将如何访问它们?有这么多用户,您通常需要应用一些过滤和/或分页,因此无论如何您都需要执行查询(除非您使用集合过滤,这对我来说看起来像一个 hack)。在这种情况下,一些开发人员可能倾向于在内存中应用过滤,这显然不利于性能。请注意,拥有这样的关系可以鼓励这种开发人员在不考虑性能影响的情况下使用它。
您将如何将新用户添加到组中?幸运的是,Hibernate 在持久化关系时会查看关系的拥有方,因此您只能设置 User.group。但是,如果要使内存中的对象保持一致,还需要将 User 添加到 Group.users 中。但它会让 Hibernate 从数据库中获取 Group.users 的所有元素!
所以,我不能同意Best Practices 的建议。您需要仔细设计双向关系,考虑用例(您是否需要双向导航访问?)和可能的性能影响。
也可以看看:
阻止 JPA 模型中的“ToMany”关系
Hibernate 映射集合性能问题
有两个主要区别。
访问关联方
第一个与您将如何访问关系有关。对于单向关联,您只能从一端导航关联。
因此,对于单向 @ManyToOne
关联,这意味着您只能从外键所在的子端访问关系。
如果您有单向 @OneToMany
关联,则意味着您只能从管理外键的父端访问关系。
对于双向 @OneToMany
关联,您可以通过两种方式导航关联,无论是从父端还是从子端。
表现
第二个方面与性能有关。
对于@OneToMany,单向关联的性能不如双向关联。对于@OneToOne,如果 Hibernate 无法判断是否应该分配 Proxy 或 null 值,则双向关联将导致急切地获取父级。对于@ManyToMany,集合类型有很大的不同,因为集合比列表表现更好。
from the child side where the foreign key resides.
from the parent side where the foreign key resides.
@ManyToMany @JoinTable(name = "role_privileges", joinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "privilege_id", referencedColumnName = "id") }) private Set<Privilege> privileges=new HashSet<Privilege>();
我不是 100% 确定这是唯一的区别,但这是主要区别。 Hibernate 文档还建议进行双向关联:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
具体来说:
首选双向关联:单向关联更难查询。在大型应用程序中,几乎所有关联都必须在查询中双向导航。
我个人对这个一揽子建议有一个小问题——在我看来,在某些情况下,孩子没有任何实际理由了解其父母(例如,为什么订单项目需要知道它的订单相关联?),但我确实在合理的时间内看到了它的价值。而且由于双向性并没有真正伤害任何东西,我不觉得坚持它太令人反感。
在编码方面,双向关系实现起来更复杂,因为应用程序负责根据 JPA 规范 5(第 42 页)使双方保持同步。不幸的是,规范中给出的例子没有给出更多细节,所以它没有给出复杂程度的概念。
当不使用二级缓存时,没有正确实现关系方法通常不是问题,因为实例在事务结束时被丢弃。
当使用二级缓存时,如果由于错误实现的关系处理方法而损坏了任何东西,这意味着其他事务也会看到损坏的元素(二级缓存是全局的)。
正确实现的双向关系可以使查询和代码更简单,但如果它在业务逻辑方面没有真正意义,则不应使用。
不定期副业成功案例分享
addUser()
调用setGroup()
以保持双方一致。addUser()
的情况下调用setGroup()
,但这会导致内存中对象的状态不一致。