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

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年后,您了解了为什么我对使用Lists vs Sets持怀疑态度。

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

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或合并Child 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ue正则

1 删除含某些内容的行,例:含有PTTAddress 使用替换功能,勾选正则表达式(Regular Expressions),查找为%*PTTAddress*^p,替换为空 2.替换大写字母为_大写字母 替换功能,查找为 ^([A-Z]^),替换为 _^1转载于:https://www.c…

20 存储过程

一、存储过程的定义 存储过程是存储在数据库目录中的一坨的声明性SQL语句。 Java,Python,PHP等应用程序可以调用存储过程。 MySQL是最受欢迎的开源RDBMS,被社区和企业广泛使用。 然而,在它发布的第一个十年期间,它不支…

微信小程序下拉框

微信小程序组件里没有下拉框&#xff0c;正好要用到&#xff0c;记下来以后参考 wxml代码 <view classtop><view classtop-text> 选择接收班级</view><!-- 下拉框 --><view classtop-selected bindtapbindShowMsg><text>{{grade_name}}&l…

int最大值java_Java 中一个int型数组的求最大值最小值 | 学步园

小友今日看单元测试&#xff0c;发现的一个测试用例的代码。而测试的是某个类的最大值&#xff0c;最小值方法。在此把测试类发上来。保留此地&#xff0c;如有人对此有兴趣&#xff0c;看以看下。闲话少说&#xff1a;public class MaxMinTool {public static int getMax(int[…

使用Maven实施自定义JSF 2.0组件

前一段时间&#xff0c;我编写了自己的定制JSF组件。 但是在那个时候&#xff0c;JSF 1.0仍然是最新的&#xff0c;并且该项目没有使用maven作为构建系统。 因此&#xff0c;我一直想用maven编写一个自定义JSF2组件。 因此&#xff0c;让我们开始&#xff1a; 首先&#xff0c…

python2.7.5-虚拟环境搭建

virtualenv可以搭建虚拟且独立的python运行环境, 使得单个项目的运行环境与其它项目独立起来. virtualenv本质上是个python包, 使用pip安装: pip install virtualenv 在新建工作目录下创建虚拟环境: ~$virtualenv TestEnv 默认情况下, 虚拟环境中不包括系统的site-packages, 若…

CSS 高度(css height)

DIV CSS height高度知识教程篇 DIV CSS高度简介这里的CSS高度是指通过CSS来控制设置对象的高度。使用CSS属性单词height。单位可以使用PX&#xff0c;em等常用使用PX&#xff08;像素&#xff09;为html单位。 height高度目录height高度语法高度用法html原始高度设置css高度hei…

fst java_java快速序列化库FST

FST fast-serialization 是重新实现的 Java 快速对象序列化的开发包。序列化速度更快(2-10倍)、体积更小&#xff0c;而且兼容 JDK 原生的序列化。要求 JDK 1.7 支持。Maven&#xff1a;12 de.ruedigermoeller3 fst4 1.365示例代码&#xff1a;01// ! reuse this Object, it ca…

HOW-TO:带有Spring MVC的Tomcat中的自定义错误页面

默认的Tomcat错误页面看起来很可怕。 此外&#xff0c;它们可能会公开有价值的信息&#xff0c;包括服务器版本和异常堆栈跟踪。 Servlet规范提供了一种通过web.xml配置异常行为的方法。 可以配置对特定Java异常的响应&#xff0c;也可以配置对选定的Http响应代码的响应。 err…

第三代酷睿i3处理器_轻薄本CPU谁更强?英特尔21款低功耗处理器大排行!

点击上电脑爱好者关注我们对智能手机而言&#xff0c;其搭载的SoC是衡量性能强弱的唯一准绳&#xff0c;因为一颗SoC芯片内就集成了CPU(处理器)、GPU(显卡&#xff0c;包括集成的核显和独显)、ISP(影像处理器)和Modem(调制解调器)等模块&#xff0c;只要掌握了SoC的强弱关系&am…

**优化--后端**: 计数缓存counter_cache; rack-mini-profiler(2300) ; bullet(5000✨):侦测N+1query...

rack-mini-profiler 这个 gem,可以永远显示网页的加载时间。&#xff08;2300✨&#xff09;开发环境和产品环境都可以用。&#xff08;生成非常详细的报告&#xff09; development环境,直接使用gem rack-mini-profilerproduction环境&#xff0c;1. gem rack-mini-profiler,…

python学习日记(匿名函数)

匿名函数 简介 匿名函数&#xff1a;为了解决那些功能很简单的需求而设计的一句话函数。 python 使用 lambda 来创建匿名函数。 所谓匿名&#xff0c;意即不再使用 def 语句这样标准的形式定义一个函数。 1 lambda 只是一个表达式&#xff0c;函数体比 def 简单很多。 2 lambda…

列表相关元素及其属性

HTML5保留了如下几个列表相关元素&#xff1a;无序列表<ul>、有序列表<ol>、自定义列表<dl> 1、<ul>&#xff1a;定义无序列表&#xff0c;可以指定id、style、class等属性&#xff0c;还可以指定onclick等事件属性。 2、<ol>&#xff1a;定义有…

唯一的hashCodes不足以避免冲突

有一个常见的误解&#xff0c;即如果您具有唯一的hashCode&#xff08;&#xff09;&#xff0c;则不会发生冲突。 虽然唯一或几乎唯一的hashCodes很好&#xff0c;但这还不是故事的结局。 问题在于HashMap的大小不是无限的&#xff08;或大小至少为2 ^ 32&#xff09;&#x…

Spring Boot使用AOP实现拦截某个方法

1、引入.jarl文件依赖 <!-- Spring Boot Web 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 从依赖信息里移除 Tomcat配置 --><exclusions><exc…

DB 数据同步到数据仓库的架构与实践

背景 在数据仓库建模中&#xff0c;未经任何加工处理的原始业务层数据&#xff0c;我们称之为ODS&#xff08;Operational Data Store&#xff09;数据。在互联网企业中&#xff0c;常见的ODS数据有业务日志数据&#xff08;Log&#xff09;和业务DB数据&#xff08;DB&#xf…

起名与选择器~(总结类、持续更新系列)

废话没有&#xff0c;直接干活 一、起名方式&#xff1a;1.元素自身的标签名&#xff1b; 2.利用 class 属性自定义名称&#xff1b; 3.利用 id 属性自定义名称。共三种&#xff0c;其中class使用居多。 起名规范:不能用汉字起 第一个字母不能是特殊符号 第一个字母必须是英文字…

java log.error_Logger.error打印错误异常的详细堆栈信息

一、问题场景使用Logger.error方法时只能打印出异常类型&#xff0c;无法打印出详细的堆栈信息&#xff0c;使得定位问题变得困难和不方便。二、先放出结论Logger类下有多个不同的error方法&#xff0c;根据传入参数的个数及类型的不同&#xff0c;自动选择不同的重载方法。当e…

笔记本电脑怎么清理灰尘_手机声音越用越小怎么办?一段黑科技音波就能清理扬声器灰尘...

大家好&#xff0c;欢迎收看科技狐&#xff0c;我是小狐。我们都知道&#xff0c;随着手机的使用时间越来越长&#xff0c;手机扬声器里面会积赞一些灰尘。因此手机的声音就会变得越来越小。有时候连电话铃声都听不清楚&#xff0c;说实话我就是这个样子&#xff0c;为此我困扰…

Java方法中的参数太多,第8部分:工具

在我的系列文章的前七篇文章中&#xff0c;有关处理Java方法中期望的参数过多的内容集中在减少方法或构造函数期望的参数数量的替代方法上。 在本系列的第八篇文章中&#xff0c;我将介绍一些工具&#xff0c;这些工具可帮助您确定可能存在过多参数的情况&#xff0c;并在出现这…