Hibernate是一个很棒的ORM工具,它极大地简化了开发,但是如果您想正确地使用它,则有很多陷阱。

在大中型项目中,双向父子关联非常常见,这使我们能够浏览给定关系的两端。

在控制关联的持久/合并部分时,有两个可用选项。 其中将有负责同步收集变化的@OneToMany结束,但是这是一个低效率的做法,这是很好的描述在这里 。

最常见的方法是@ManyToOne端控制关联并且@OneToMany端使用“ mappedBy”选项时。

我将讨论后一种方法,因为就执行的查询数量而言,这是最常见,最有效的方法。

因此,对于双向集合,我们可以使用java.util.List或java.util.Set。

根据Hibernate docs的说法,列表和文件包比集合更有效。

但是当我看到以下代码时,我仍然感到焦虑:

@Entity
public class Parent {...@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true)
private List children = new ArrayList()public List getChildren() {
return children;
}public void addChild(Child child) {
children.add(child);
child.setParent(this);
}public void removeChild(Child child) {
children.remove(child);
child.setParent(null);
}
}@Entity
public class Child {...@ManyToOne
private Parent parent;public Parent getParent() {
return parent;
}public void setParent(Parent parent) {
this.parent = parent;
}
}Parent parent = loadParent(parentId);
Child child1 = new Child();
child1.setName("child1");
Child child2 = new Child();
child2.setName("child2");
parent.addChild(child1);
parent.addChild(child2);
entityManager.merge(parent);

这是因为在最近五年中,当在父关联上调用合并操作时,我一直在插入重复的子代。 发生这种情况是由于以下问题: HHH-3332和HHH-5855 。

我最近一直在测试一些Hibernate版本,并且仍然在3.5.6、3.6.10和4.2.6版本上进行复制。 因此,经过5年在许多项目上看到这一点后,您了解了为什么我对使用列表与集合持怀疑态度。

这是在运行复制此问题的测试用例时得到的结果,因此添加两个子级,我们得到:

select parent0_.id as id1_2_0_ from Parent parent0_ where parent0_.id=?
insert into Child (id, name, parent_id) values (default, ?, ?)
insert into Child (id, name, parent_id) values (default, ?, ?)
insert into Child (id, name, parent_id) values (default, ?, ?)
insert into Child (id, name, parent_id) values (default, ?, ?)

仅当合并操作从父级到子级联时,才会出现此问题,并且存在以下变通办法:

  • 合并孩子而不是父母
  • 在合并父母之前先让孩子坚持
  • 从父级删除Cascade.ALL或Cascade.MERGE,因为它只影响合并操作,而不影响持久化操作。

但是所有这些都是黑客,在大型项目中很难遵循,因为许多开发人员都在相同的代码库上工作。

因此,我的首选方式是使用Set,即使有时它们的效率不如Lists更好,但是由于我一直偏爱正确性与性能优化,因此最好使用Set。

当涉及到这类问题时,最好具有代码约定,因为它们易于添加到项目开发指南中,并且易于记忆和采用。

使用集合的一个优点是,它迫使您定义适当的equals / hashCode策略(该策略应始终包括实体的业务密钥。业务密钥是一种字段组合,该字段组合在父级的子级中是唯一的或唯一的,并且甚至在之前也是一致的)以及将实体持久保存到数据库中之后)。

如果您担心会失去以添加孩子的相同顺序保存孩子的“列表”功能,那么您仍然可以为Sets模仿。

默认情况下,集合是无序的和未排序的,但是即使您不能对它们进行排序,也可以通过使用@OrderBy JPA注释按给定的列对它们进行排序,如下所示:

@Entity
public class LinkedParent {...@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true)
@OrderBy("id")
private Set children = new LinkedHashSet();...public Set getChildren() {
return children;
}public void addChild(LinkedChild child) {
children.add(child);
child.setParent(this);
}public void removeChild(LinkedChild child) {
children.remove(child);
child.setParent(null);
}
}

加载父级的子级时,生成SQL类似于:

select children0_.parent_id as parent_i3_3_1_, children0_.id as id1_2_1_, children0_.id as id1_2_0_, children0_.name as name2_2_0_, children0_.parent_id as parent_i3_2_0_ from LinkedChild children0_ where children0_.parent_id=? order by children0_.id

结论:

如果您的领域模型要求使用列表而不是集合,则将打破您的约束,不允许重复。 但是,如果您需要重复项,则仍然可以使用索引列表。 据说Bag是未排序且“无序的”(即使它按照在数据库表中添加子的顺序来检索子)。 因此,索引列表也将是一个不错的选择,对吗?

我还想提请注意一个5年的bug,它影响了多个Hibernate版本,并且是我在多个项目中复制的一个版本。 当然,有一些解决方法,例如删除Cascade.Merge或合并Children vs the Parent,但是有许多开发人员不知道此问题及其解决方法。

根据Hibernate docs:集是“ 表示多值关联的推荐方法 ”,而且我已经看到很多情况下使用Bags作为默认双向集合,即使无论如何集都是更好的选择。

因此,我仍然对Bags保持谨慎,如果我的领域模型强加使用List,我总是会选择索引的。

  • 代码可在GitHub上获得 。
参考: Hibernate Facts:来自Vlad Mihalcea博客博客的JCG合作伙伴 Vlad Mihalcea偏爱双向集合与列表 。

翻译自: https://www.javacodegeeks.com/2013/10/hibernate-facts-favoring-bidirectional-sets-vs-lists.html

Hibernate事实:有利于双向集vs列表相关推荐

  1. 休眠事实:有利于双向集vs列表

    Hibernate是一个很棒的ORM工具,它极大地简化了开发,但是如果您想正确地使用它,则有很多陷阱. 在大中型项目中,具有双向父子关联非常常见,这使我们能够浏览给定关系的两端. 在控制关联的持久/合 ...

  2. myeclipse hbm2java_myeclipse试用小记----Hibernate多对一双向关联(2)

    myeclipse试用小记----Hibernate多对一双向关联(2) 在上篇文章"myeclipse试用小记----Hibernate多对一单向关联(1)"中,讲到了" ...

  3. myeclipse试用小记----Hibernate多对一双向关联(2)

    myeclipse试用小记----Hibernate多对一双向关联(2) 在上篇文章"myeclipse试用小记----Hibernate多对一单向关联(1)"中,讲到了" ...

  4. Kafka的灵魂伴侣Logi-KafkaManger(3)之运维管控--集群列表

    推荐一款非常好用的kafka管理平台,kafka的灵魂伴侣 滴滴开源Logi-KafkaManager 一站式Kafka监控与管控平台 技术交流 有想进滴滴LogI开源用户群的加我个人微信: jjdl ...

  5. vue 单相绑定_Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)...

    Vuejs第一篇之入门教程详解(单向绑定.双向绑定.列表渲染.响应函数) 2018-12-30 什么是组件? 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素 ...

  6. vue 双向绑定,列表、条件渲染,解决强制刷新闪烁问题

    vue 双向绑定 v-model 列表渲染 v-for 条件渲染 v-if v-show 解决强制刷新闪烁问题 v-clock 双向绑定 v-model v-model 是 vue 中进行数据双向绑定 ...

  7. list 去重_测试面试题集Python列表去重

    ------·今天距2020年21天·------ 这是ITester软件测试小栈第86次推文 请定义函数,将列表[10, 1, 2, 20, 10, 3, 2, 1, 15, 20, 44, 56, ...

  8. 【Hibernate步步为营】--双向关联一对一映射具体解释(一)

    一对一的映射在对象模型中是常常见到的,为了将对象模型转换为关系模型就必须在映射文件里进行配置,上篇文章讨论了一对一映射的单向关联的情况,重点是<one-to-one>标签的使用,须要在映射 ...

  9. Hibernate关联关系映射-----双向一对多/多对一映射配置

    转自:http://blog.csdn.net/yifei12315/article/details/6985194 /// Hibernate: /// 双向关联就是有"一对多" ...

最新文章

  1. java webservice 身份验证_java-Http基本身份验证不适用于Spring WS和WebS...
  2. STM32之中断嵌套控制器
  3. 安装java环境_(一)环境安装之Java
  4. python搜索关键词自动提交_简单爬虫:调用百度接口,实现关键词搜索(python_003)...
  5. python hash函数_Python hash()函数
  6. npm install 报错operation not permitted, unlink
  7. Vue.js尚硅谷视频学习笔记(第一章:Vue 核心)
  8. Arduino PS2手柄小车代码
  9. 有限元基础及ANSYS应用 - 第4节 - 平面桁架结构的ANSYS分析
  10. 机器学习与量化交易项目班 [从零搭建自动交易系统]
  11. nginx网关与gateway网关的区别
  12. codeforces 696C C. PLEASE(概率+快速幂)
  13. CSCD刊源(2007年-2008年)
  14. 长尾分布(long-tail distribution)和长尾效应
  15. Java中生产者和消费者总结
  16. MySQL基础语法与JDBC
  17. ouster-32激光雷达实测:ROS驱动编译使用与设备连接的网络配置
  18. NC65 自由报表开发
  19. 《游戏开发物理学(第2版)》一1.6 质量、质心和转动惯量
  20. verilog_边学边练习(5) 秒计数器(时序逻辑电路)

热门文章

  1. 2018年10月17日普级B组【模拟赛】
  2. [XSY] 智慧树(线性同余方程组,线段树/树状数组)
  3. Sentinel(一)之简介
  4. java并发编程之4——Java锁分解锁分段技术
  5. Java 内存模型 JMM 详解
  6. java实现人脸识别源码【含测试效果图】——Service层(IUserService)
  7. 调用阿里云接口实现短信消息的发送源码——CSDN博客
  8. 2015蓝桥杯省赛---java---A---8(移动距离)
  9. JAVASE阶段流程图
  10. python定义函数prime判断是否是素数_用自定义函数判断素数 用C语言编写自定义函数prime(int x),判断x是否为素数?...