hibernate语句_如何优化Hibernate EllementCollection语句
hibernate语句
介绍
Hibernate支持三种数据映射类型 : 基本 (例如String,int), Embeddable和Entity 。 通常,数据库行被映射到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语句
hibernate语句_如何优化Hibernate EllementCollection语句相关推荐
- mysql使索引失效语句_会导致索引失效语句
1.使用like关键字模糊查询时,% 放在前面索引不起作用,只有"%"不在第一个位置,索引才会生效(like '%文'–索引不起作用) 2.使用联合索引时,只有查询条件中使用了这些 ...
- java任何表达式都可以当作语句_在Java语言中语句用分号终止,并不是所有的表达式都可以构成语句...
在Java语言中,语句以分号":"作为结束标志.块语句由其他语句组成,其本身不需要用分号结尾.另外,内嵌有块语句并以块语句结尾的语句,也不需要用分号结尾. Java语句可分为空语句 ...
- hibernate自定义_如何自定义Hibernate脏检查机制
hibernate自定义 介绍 在上一篇文章中,我描述了Hibernate自动脏检查机制. 尽管您应该始终喜欢它,但是有时您可能想添加自己的自定义污垢检测策略. 自定义脏检查策略 Hibernate提 ...
- hibernate示例_通过示例Hibernate–第1部分(删除孤儿)
hibernate示例 所以我想做一系列的冬眠例子,展示冬眠的各种特征. 在第一部分中,我想展示有关删除孤儿功能及其在故事情节中的使用方式. 因此,让我们开始:) 先决条件 : 为了尝试以下示例,您将 ...
- python中try语句_[转]python 里面 try语句
python的try语句有两种风格 一:种是处理异常(try/except/else) 二:种是无论是否发生异常都将执行最后的代码(try/finally) try/except/else风格 try ...
- sql select 语句_学习SQL:SELECT语句
sql select 语句 The SELECT statement is probably the most important SQL command. It's used to return r ...
- python判断语句_详解Python判断语句的使用方法
本篇介绍Python判断语句的使用,主要讨论简单条件语句.多重条件语句和嵌套条件语句,在讲解的每个案例中都配有流程图和代码说明.通过本篇的学习,可以达成如下目标. ● 掌握判断语句的使用规则 ● 判断 ...
- mysql 怎么查询慢sql语句_如何优化MySQL中查询慢的SQL语句啊?
追问 恩恩我对sql稍微了解点 不知道怎么优化慢sql 可以指导一下嘛 谢谢啦 可以加下我qq吗 1501630150来自:求助得到的回答 mysql数据库有100万+数据,查询起来很慢了,如何优化 ...
- mysql hql查询语句_使用Query进行HQL语句查询和SQL语句查询
HQL的语法比较简单,与普通SQL的区别之处是针对对象的不同,在查询语句中将sql中的表名替换成了sql中的持久化类名,因为hibernate机制是基于对象进行查询的. 不带参数的查询,语句是&quo ...
最新文章
- 查看微码的两种方式hmcaix
- 真正的 Tornado 异步非阻塞
- 京东到家休闲食品即时消费趋势报告
- 没有主清单属性_梦幻西游电脑版:神威组第一大唐?大佬两天更新200W硬件,这身属性难被超越!太狠了...
- FFT变换频谱图中幅值的设置方法
- 客户端控件Javascript验证类
- Elastic Search Java Api 创建索引结构,添加索引
- 北航 2011年考研复试题2
- 为知笔记linux输入中文,为知笔记wiznote无法输入中文,fcitx输入法问题解决
- 日照科技中等专业学校 远程预付费系统的设计与应用
- 【生物信息】 系统发育树-有根树 转化 无根树-基于R语言
- java 正则校验经纬度格式
- 【全局路径规划】A*算法 A* Search Algorithm
- Avro RPC 之 Protocol 定义和代码生成
- HBase环境搭建与基本使用(保姆级教程)
- 软件测试人员能力矩阵
- 经济危机与金融危机的学术解释与通俗到庸俗的解释,包你明白
- python wifi 切换网络
- 积分制管理系统:任务发布和审核
- 通过MATLAB模拟24个GPS卫星的轨道运行效果