hibernate语句_如何优化Hibernate EllementCollection语句

hibernate语句

介绍

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

这两种基本类型和Embeddables可以通过被关联到一个实体 @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提供程序都将需要从实体的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

hibernate语句

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

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

相关文章

C++ 虚函数表剖析

点击蓝字关注我们一、概述为了实现C的多态&#xff0c;C使用了一种动态绑定的技术。这个技术的核心是虚函数表&#xff08;下文简称虚表&#xff09;。本文介绍虚函数表是如何实现动态绑定的。二、类的虚表每个包含了虚函数的类都包含一个虚表。我们知道&#xff0c;当一个类&a…

aix pax_通过Pax考试对JBoss Fuse 6.x进行集成测试,第一部分

aix paxJBoss Fuse是一个功能强大的分布式集成平台&#xff0c;具有内置功能&#xff0c;可用于针对集成的微服务部署进行集中式配置管理&#xff0c;服务发现&#xff0c;版本控制&#xff0c;API网关&#xff0c;负载平衡&#xff0c;故障转移等。 JBoss Fuse 6.x构建在Fabri…

android王者调不了界面,王者荣耀登录界面怎么改?登录界面更改教程[多图]

王者荣耀登录界面怎么改&#xff1f;许多玩家都想更改自己登陆的界面&#xff0c;但是都不清楚&#xff0c;下面就让安卓乐园小编为大家带来&#xff0c;登录界面更改教程。王者荣耀登录界面怎么改&#xff1f;1、安卓手机打开文件管理&#xff0c;找到根目录下Android/data/co…

y空间兑换代码_Python爬虫实战:QQ空间全自动点赞工具

QQ空间自动点赞前景提要目标确定分析介绍登陆获取cookie寻找XML寻找可变参数获取第一个空间动态寻找点赞所需的URL寻找可变参数功能提升到秒赞全部代码最后还是希望你们能给我点一波小小的关注。奉上自己诚挚的爱心私信小编01即可获取大量Python学习资料前景提要因为我周围的小…

学点 STL C++ 无序容器和元组

点击蓝字关注我们无序容器我们已经熟知了传统 C 中的有序容器 std::map/std::set&#xff0c;这些元素内部通过红黑树进行实现&#xff0c; 插入和搜索的平均复杂度均为 O(log(size))。在插入元素时候&#xff0c;会根据 < 操作符比较元素大小并判断元素是否相同&#xff0c…

html中的文档格式及举例,跟我一起从零开始学习WebAssembly(三)、最简单的例子hello world(使用自定义HTML模板)...

文章目录创建C代码片创建我们的自定义HTML模板文件编译运行实例有时我们想要使用我们自定义HTML模板。让我们来看看我们如何做到这一点。创建C代码片首先&#xff0c;创建一个名为hello2的目录。其次&#xff0c;在该目录下创建一个名为hello2.c文件。并将以下C代码保存在文件中…

设计模式适配器模式_21世纪的设计模式:适配器模式

设计模式适配器模式这是我的演讲的第三部分&#xff0c;“ 21世纪的设计模式” 。 适配器模式桥接世界。 在一个世界中&#xff0c;我们有一个概念的界面。 在另一个世界&#xff0c;我们有不同的界面。 这两个接口有不同的用途&#xff0c;但有时我们需要进行转移。 在编写良…

excel单元格斜线_掌握这20个Excel技巧,小白轻松变大神

掌握一些Excel小技巧&#xff0c;可以让你的工作效率翻倍&#xff0c;原本半个小时才能搞定的&#xff0c;现在几秒就可以轻松搞定。1、调整单元格大小选中表格&#xff0c;将光标移到表格顶部边框处&#xff0c;等其变成双向箭头即可移动。2、快速插入空行选中行&#xff0c;按…

html鼠标滚动效果代码,JS+CSS实现大气清新的滑动菜单效果代码

本文实例讲述了JSCSS实现大气清新的滑动菜单效果代码。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这是一款比较大气清新的滑动导航菜单&#xff0c;CSS和JavaScript配合完成&#xff0c;鼠标放到一级菜单上&#xff0c;会滑出二级的菜单&#xff0c;兼容性也不错&a…

docker和java容器_使用Docker容器和Java EE进行持续交付

docker和java容器组织需要一种使应用程序交付快速&#xff0c;可预测和安全的方法&#xff0c;而诸如docker之类的容器所提供的敏捷性则可以帮助开发人员实现这一目标。 对于Java EE应用程序&#xff0c;这可以在容器中打包应用程序&#xff0c;应用程序服务器和其他依赖项&…

alientek ministm32液晶显示程序_佳显12864中文字库液晶专业生产液晶显示模块

GDRAM&#xff1a;(Graphic Display RAM)&#xff1a;图形显示RAM&#xff0c;这一块区域用于绘图&#xff0c;往里面写啥&#xff0c;屏幕就会显示啥&#xff0c;它与DDRAM的区别在于&#xff0c;往DDRAM中写的数据是字符的编码&#xff0c;字符的显示先是在CGROM中找到字模&a…

C++ 面试考点(一)

点击蓝字关注我们C 基础1、引用和指针的区别&#xff1f;初始化:引用在定义的时候必须进行初始化&#xff0c;并且不能够改变指针在定义的时候不一定要初始化&#xff0c;并且指向的空间可变访问逻辑不同:通过指针访问对象, 用户需要使用间接访问通过引用访问对象, 用户只需使用…

dojo还有人用吗_我的Dojo中有一个Mojo(如何编写Maven插件)

dojo还有人用吗我一直忙于在工作中使用Maven的腋窝。 对于很多开发人员&#xff0c;我会听到&#xff1a;“那又怎样。” 区别在于&#xff0c;我通常在无法直接访问Internet的环境中工作。 因此&#xff0c;当我说我经常使用Maven时&#xff0c;这意味着某些事情。 依赖地狱 …

html5 css3炫酷效果,28种纯CSS3炫酷loading加载动画特效

这是一组效果非常炫酷的纯CSS3 Loading加载动画特效。这组loading动画共有27种不同的效果。每一种loading动画都是通过CSS3的keyframes帧动画来完成的&#xff0c;每一个加载动画都构思新颖&#xff0c;效果非常的酷。安装可以通过bower来按钮这个loading动画特效&#xff1a;b…

中点和中值滤波的区别_频谱仪和EMI测试接收机什么区别?安泰维修中心分享

测试人员在选择使用射频仪器的时候都在纠结选择频谱仪还是测试接收机又或者信号分析仪。下面由安泰频谱分析仪维修中心分享频谱仪和EMI测试接收机什么区别&#xff1f;测量接收机是什么&#xff1f;频谱仪和信号分析仪什么区别&#xff1f;信号源分析仪是什么&#xff1f;一、频…

C++ 面试必问:深入理解虚函数表

点击蓝字关注我们深入理解C 虚函数表C中的虚函数的作用主要是实现了多态的机制。关于多态&#xff0c;简而言之就是用父类型别的指针指向其子类的实例&#xff0c;然后通过父类的指针调用实际子类的成员函数。Derive d; Base1 *b1 &d; Base2 *b2 &d; Base3 *b3 &…

html 图片剪裁压缩,HTML5 canvas实现图片拉伸、压缩与裁剪

前言&#xff1a;我们在网页中经常会用到图片展示&#xff0c;通常情况下会给一个固定的宽高来显示这个图片&#xff0c;然而从服务器端上传的图片大小是不确定的&#xff0c;如果直接按默认填充这个框有时候就会特别丑orz。作为一个完(wai)美(mao)主(xie)义(hui)者&#xff0c…

switch日文键盘打中文_12月有哪些Switch游戏值得期待?

文章转自A9vg&#xff0c;作者setsuka_duki 经历了11月的游戏浪潮后&#xff0c;一年中最后一个月份也悄然而至&#xff0c;相比较“战火连天”的11月&#xff0c;在12月发售的重量级游戏并不算太多&#xff0c;这边为大家整理12月哪些值得一玩的Switch游戏。 《Tools Up!》(分…

基于 C++11 的线程池 threadpool , 简洁且可以带任意多的参数

点击蓝字关注我们咳咳。C11 加入了线程库&#xff0c;从此告别了标准库不支持并发的历史。然而 c 对于多线程的支持还是比较低级&#xff0c;稍微高级一点的用法都需要自己去实现&#xff0c;譬如线程池、信号量等。线程池(thread pool)这个东西&#xff0c;在面试上多次被问到…

c# 字典排序_Python零基础入门之列表与字典

本篇内容需结合源码&#xff0c;获取方法看末尾数据结构数据结构就是指从计算机存储、组织数据的结构列表(List) 元组(Tuple)字典(Dictionary)集合(Set)列表(List)列表中的数据按顺序排列列表有正序与倒序两种索引列表可存储任意类型数据&#xff0c;且允许重复创建列表变量名 …