如何优化Hibernate EllementCollection语句

介绍

Hibernate支持三种数据映射类型 : 基本 (例如String,int), EmbeddableEntity 。 通常,数据库行映射到Entity ,每个数据库列都与一个基本属性关联。 当将多个字段映射组合到一个可重用的组中时, 可嵌入的类型更为常见( Embeddable被合并到拥有的实体映射结构中)。

基本类型和可嵌入对象都可以通过@ElementCollection ,以一个实体-很多-非实体的关系关联到一个实体

测试时间

对于即将到来的测试用例,我们将使用以下实体模型:

要素收集补丁变更

修补程序具有变更可嵌入对象的集合。

@ElementCollection
@CollectionTable(name="patch_change",joinColumns=@JoinColumn(name="patch_id")
)
private List<Change> changes = new ArrayList<>();

Change对象建模为Embeddable类型,并且只能通过其所有者Entity进行访问。 Embeddable没有标识符 ,因此无法通过JPQL查询。 Embeddable生命周期绑定到其所有者的生命周期,因此任何实体状态转换都会自动传播到Embeddable集合。

首先,我们需要添加一些测试数据:

doInTransaction(session -> {Patch patch = new Patch();patch.getChanges().add(new Change("README.txt", "0a1,5..."));patch.getChanges().add(new Change("web.xml", "17c17..."));session.persist(patch);
});

添加一个新元素

让我们看看将新的Change添加到现有Patch时会发生什么:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(new Change("web.xml", "1d17..."));
});

此测试生成以下SQL输出:

DELETE FROM patch_change 
WHERE  patch_id = 1INSERT INTO patch_change (patch_id, diff, path)
VALUES (1, '0a1,5...', 'README.txt') INSERT INTO patch_change(patch_id, diff, path)
VALUES (1, '17c17...', 'web.xml') INSERT INTO patch_change(patch_id, diff, path)
VALUES (1, '1d17...', 'web.xml')

默认情况下,任何收集操作最终都会重新创建整个数据集。 这种行为仅对于内存中的集合是可接受的,并且从数据库的角度来看是不合适的。 数据库必须删除所有现有的行,而只是重新添加它们的后缀。 我们在此表上拥有的索引越多,性能损失就越大。

删除元素

删除元素没有什么不同:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(0);
});

此测试用例生成以下SQL语句:

DELETE FROM patch_change 
WHERE  patch_id = 1INSERT INTO patch_change(patch_id, diff, path)
VALUES (1, '17c17...', 'web.xml')

删除了所有表行,并将剩余的内存中条目刷新到数据库中。

Java Persistence Wiki Book清楚地记录了这种行为:

JPA 2.0规范没有提供在Embeddable中定义ID的方法。 但是,要删除或更新ElementCollection映射的元素,通常需要一些唯一键。 否则,在每次更新时,JPA提供程序都需要从Entity的CollectionTable中删除所有内容,然后将这些值重新插入。 因此,JPA提供程序将最有可能假定Embeddable中所有字段的组合与外键(JoinColumn(s))组合在一起是唯一的。 但是,如果Embeddable很大或很复杂,这可能效率很低,或者根本不可行。

一些JPA提供程序可能允许在可嵌入对象中指定ID,以解决此问题。 请注意,在这种情况下,Id仅对于集合(表)而言是唯一的,因为其中包括外键。 有些可能还允许将CollectionTable上的唯一选项用于此目的。 否则,如果您的Embeddable很复杂,则可以考虑将其设为实体,而改用OneToMany。

添加一个OrderColumn

为了优化ElementCollection行为,我们需要应用适用于一对多关联的相同技术。 元素的集合就像是单向的一对多关系,并且我们已经知道idbag的 性能比单向bag更好 。

因为可嵌入对象不能包含标识符,所以我们至少可以添加一个订单列,以便可以唯一地标识每一行。 让我们看看将@OrderColumn添加到元素集合时会发生什么:

@ElementCollection
@CollectionTable(name="patch_change",joinColumns=@JoinColumn(name="patch_id")
)
@OrderColumn(name = "index_id")
private List<Change> changes = new ArrayList<>();

删除实体后,以前的测试结果没有任何改善:

DELETE FROM patch_change 
WHERE  patch_id = 1INSERT INTO patch_change(patch_id, diff, path)
VALUES (1, '17c17...', 'web.xml')

这是因为在阻止重新创建集合时, AbstractPersistentCollection将检查可为空的列:

@Override
public boolean needsRecreate(CollectionPersister persister) {if (persister.getElementType() instanceof ComponentType) {ComponentType componentType = (ComponentType) persister.getElementType();return !componentType.hasNotNullProperty();}return false;
}

现在,我们将添加NOT NULL约束并重新运行测试:

@Column(name = "path", nullable = false)
private String path;@Column(name = "diff", nullable = false)
private String diff;

添加一个新的有序元素

将元素添加到列表的末尾将生成以下语句:

INSERT INTO patch_change(patch_id, index_id, diff, path)
VALUES (1, 2, '1d17...', 'web.xml')

index_id列用于持久存储内存中的收集顺序。 添加到集合的末尾不会影响现有元素的顺序,因此仅需要一个INSERT语句。

添加一个新的第一个元素

如果我们在列表的开头添加一个新元素:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(0, new Change("web.xml", "1d17..."));
});

生成以下SQL输出:

UPDATE patch_change
SET    diff = '1d17...',path = 'web.xml'
WHERE  patch_id = 1AND index_id = 0 UPDATE patch_change
SET    diff = '0a1,5...',path = 'README.txt'
WHERE  patch_id = 1AND index_id = 1INSERT INTO patch_change (patch_id, index_id, diff, path)
VALUES (1, 2, '17c17...', 'web.xml')

现有数据库条目已更新,以反映新的内存中数据结构。 由于新添加的元素已添加到列表的开头,因此它将触发对表的第一行的更新。 所有INSERT语句在列表的末尾发出,并且所有现有元素均根据新的列表顺序进行更新。

@OrderColumn Java持久性文档中对此行为进行了说明:

当更新关联或元素集合时,持久性提供程序维护order列的值的连续(非稀疏)排序。 第一个元素的订单列值为0。

删除有序元素

如果我们删除最后一个条目:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(patch.getChanges().size() - 1);
});

仅发出一个DELETE语句:

DELETE FROM patch_change
WHERE  patch_id = 1AND index_id = 1

删除第一个元素条目

如果删除第一个元素,则会执行以下语句:

DELETE FROM patch_change
WHERE  patch_id = 1AND index_id = 1 UPDATE patch_change
SET    diff = '17c17...',path = 'web.xml'
WHERE  patch_id = 1AND index_id = 0

Hibernate删除所有多余的行,然后更新其余的行。

从中间删除

如果我们从列表中间删除一个元素:

doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().add(new Change("web.xml", "1d17..."));patch.getChanges().add(new Change("server.xml", "3a5..."));
});doInTransaction(session -> {Patch patch = (Patch) session.get(Patch.class, 1L);patch.getChanges().remove(1);
});

执行以下语句:

DELETE FROM patch_change
WHERE  patch_id = 1AND index_id = 3UPDATE patch_change
SET    diff = '1d17...',path = 'web.xml'
WHERE  patch_id = 1AND index_id = 1 UPDATE patch_change
SET    diff = '3a5...',path = 'server.xml'
WHERE  patch_id = 1AND index_id = 2

有序ElementCollection的更新如下:

  • 调整数据库表的大小, DELETE语句删除位于表末尾的多余行。 如果内存中的集合大于数据库中的集合,则所有INSERT语句将在列表的末尾执行
  • 添加/删除条目之前的所有元素均保持不变
  • 添加/删除元素之后的其余元素将更新以匹配新的内存中收集状态

结论

一对多 反向关联相比, ElementCollection更难优化。 如果集合经常更新,则最好用一对多关联替换元素集合。 当我们不想为表示外键端添加额外的实体时,元素集合更适合于很少更改的数据。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/05/how-to-optimize-hibernate-ellementcollection-statements.html

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

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

相关文章

使用Eclipse将包含第三方jar库的java工程打包成jar包

1、MANIFEST.MF 在工程下新建一个MANIFEST.MF的文件,项目结构如下。 M.java package cn.hwd.main;import java.io.IOException;import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.s…

史上最牛逼的导航网站(很全很详细)

今天,给大家推荐47个聚合型的导航网站 每一个都收录上百个网站,1个能顶100个,丝毫没有夸张的成分。 (推荐收藏) 设计师导航网站 01 优设导航 https://hao.uisdc.com/ 设计师必备的导航网站,包含设计工具、素材资源、字体设计、配色方案、酷站模板等。 界面清晰无广告…

codeforces 337D Book of Evil(dp)

转载请注明出处&#xff1a; http://www.cnblogs.com/fraud/ ——by fraud Book of Evil Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains n settlements numbered from 1 to n. Moving through the swamp is ver…

html 如何去滚动条,css怎么去除滚动条?

css可以通过overflow与scroll属性来实现去除滚动条效果。css设置overflow属性为hidden可以实现去除滚动条或设置scroll属性为no。1、这个可以用CSS实现 你可以用JS操作CSS方法一&#xff1a;设置CSS属性overflow为hidden。&#xff1c;body style"overflow:hidden"&a…

阿里云ECS服务器连接不上3306端口?

连不上3306端口一般有三种情况。 1 .本机上防火墙没有开放3306端口,需要自己配置入站规则,或者关闭本机防火墙。 2 .linux 服务器上的 iptables 防火墙没有开放3306端口, 或者关闭服务器上的防火墙。 打开 /etc/sysconfig/iptables 在 "-A INPUT –m state --sta…

UGUI 锚点

今天我们来学习下UGUI的锚点, 他是做什么的呢&#xff1f; 基本上就是用于界面布局. 1. 1个控件对应1个描点. 2. 描点分成四个小叶片, 每1个叶片 对应 控件四边框的角点 3. 不管屏幕如何放大缩小, 控件四边点与 每一个叶片对应的四边点距离不变.(换句话说,按钮的中心与描点的…

语文课外运用计算机探究,[小学语文]计算机在小学写字教学中的运用之我见

[小学语文]计算机在小学写字教学中的运用之我见随着经济的快速发展&#xff0c;教育也出现了加快发展、加快改革的势态。随着教育技术的不断增加&#xff0c;教学设备得以不断更新&#xff0c;教学手段变得更加现代化。特别是我们火星小学&#xff0c;计算机辅助教学已成为学校…

glassfish_具有GlassFish和一致性的高性能JPA –第1部分

glassfish您以前听说过连贯性吗&#xff1f; 可能是。 它是那些著名的内存网格解决方案之一&#xff0c;这些解决方案承诺了出色的快速数据访问和无限空间用于您经常使用的数据。 其中一些众所周知的竞争对手是Infinispan &#xff0c; Memcached和Terracotta Ehcache 。 它们都…

推荐几个开发高薪技术产品(APP、网站、小程序)的原型设计工具

工欲善其事必先利其器。作为一名产品经理&#xff0c;如何才能快速地设计一款产品&#xff1f;一款优秀的产品原型工具必不可少。如何才能选择一款适合自己的原型工具呢&#xff1f;Benson特意整理了11款产品原型工具以供参考&#xff0c;并学习曲线&#xff0c;性价比&#xf…

APP界面常用的五种颜色搭配

众所周知&#xff0c;每一种颜色带给用户的视觉感受也是不同的。现在人们对手机的依赖程度&#xff0c;就能看到手机中APP的发展前景&#xff0c;那今天就跟大家聊聊如何通过颜色搭配的不同来进行移动端APP界面的布局和排版设计。移动端UI界面中通常是需要选取主色&#xff0c;…

JavaOne 2015 –提交的技巧和建议

大家都知道JavaOne 。 感觉就像一直在那儿。 而且&#xff0c;即使我们跌宕起伏&#xff0c;而地理位置也不是我们想要的那样&#xff0c;旧金山也很昂贵&#xff0c;而且和。 这是有关各种Java的顶级会议。 今年又再次成为程序委员会&#xff08;“ Java&#xff0c;DevOps和云…

计算机网络课程计划,计算机网络教学计划2017

计算机网络教学计划2017教学计划(课程计划)是课程设置的整体规划&#xff0c;它规定不同课程类型相互结构的方式&#xff0c;也规定了不同课程在管理学习方式的要求及其所占比例。下面是小编整理的计算机网络教学计划范文&#xff0c;希望对你有帮助!计算机网络教学计划(一)一、…

微信服务商开发能力说明文档

最近看到很多人复制我的这篇文章,我也是醉了,你起码搞个转载,注明出处, 然后设置付费文档,发现也不好使,文章比较简短,别人也能免费看到我的文章全部内容, 无奈之下,再次打开这篇文章开始编辑, 前面增加一些废话, 看看有多少人复制我的文档,我都不想评论,找各…

html中scope的作用,AngularJS 作用域(Scope)

AngularJS 作用域(Scope)作用域(Scope)是一个存储应用数据模型的对象为 表达式 提供了一个执行上下文作用域的层级结构对应于 DOM 树结构作用域可以监听 表达式 的变化并传播事件作用域有什么作用域提供了 ($watch) 方法监听数据模型的变化作用域提供了 ($apply) 方法把不是由A…

跳转到企业缓存之前要考虑的事项

介绍 关系数据库事务是ACID &#xff0c;强大的一致性模型简化了应用程序开发。 由于启用Hibernate缓存是一项配置 &#xff0c;因此&#xff0c;只要数据访问层开始显示性能问题&#xff0c;就转向缓存非常吸引人。 添加缓存层确实可以提高应用程序性能&#xff0c;但是它有其…

(027) Linux之shell分支if语句

十年运维系列之基础篇 - Linux 作者&#xff1a;曾林 联系&#xff1a;1494445739qq.com 网站&#xff1a;www.jplatformx.com 版权&#xff1a;文章未经同意请勿转载 一、使用if语句 通过shell&#xff0c;我们可以来写出这样的一个使用if语句的shell脚本片段。如下所示&…

解锁计算机桌面,电脑锁屏按什么键解锁

按回车键即可解锁。具体的解锁过程如下1、先将电脑设置一个密码&#xff0c;再使用电脑锁屏快捷键将屏幕锁掉&#xff0c;最后按回车键解锁。首先在电脑桌面上点击开始菜单&#xff0c;找到控制面板点击并进入。2、然后在弹出的界面找到“用户账户和家庭安全”&#xff0c;并单…

ppt如何旋转流程图_张伟随笔37:我书写方程式和画流程图的方法

珠海海洋王国里的海象山张伟 2020.11.23我书写方程式和画流程图的方法首发/化学张伟/2020.05.13书写化学方程式&#xff0c;在word里面可以实现一部分&#xff0c;例如&#xff0c;我要书写高锰酸钾受热分解为锰酸钾、二氧化锰和氧气&#xff0c;化学式有上下标&#xff0c;可以…

职业技术人士学习捷径最快的网站

由于最近研究大数据相关的技术及前沿技术,对常用的几个网站做一下分享(包含技术网站+最新资讯网站): 1. 36Kr 网站:https://36kr.com/ 提供创业资讯、科技新闻、投融资对接、股权投资、极速融资等创业服务,致力成为创业者可以依赖的创业服务平台,为创业者提供最好的产品和…

单元测试编写_为什么要编写单元测试-测试技巧8

单元测试编写我对最近的博客“您应该测试什么”有很多React&#xff0c;有些人出于各种原因与我达成一致&#xff0c;另一些人则认为建议某些类可能不需要单元测试是完全危险的。 已经处理了什么测试&#xff0c;今天的博客涉及为什么要编写单元测试&#xff0c;而今天的示例代…