hibernate 映射

首先,本文的灵感来自于Burt Beckwith在2011年1月27日于SpringOne 2GX上发表的有关高级GORM –性能,自定义和监视的演讲 。 简而言之, Burt Beckwith讨论了使用映射集合和GORM中的Hibernate 2级缓存的潜在性能问题,以及避免此类性能下降的策略。

尽管如此, Burt Beckwith在演讲中指出的有关映射集合的性能问题通常适用于每个启用Hibernate的应用程序。 这就是为什么看完他的演讲后我才意识到他的提议正是我自己一直在做的事情,并指示我的同事在使用Hibernate中的 映射集合进行开发时应该做。

以下是使用Hibernate 映射集合时要考虑的5件事:

让我们考虑以下经典的“图书馆–访问”示例:

以下Library类具有Visit实例的集合:

package eg;
import java.util.Set;public class Library {private long id;private Set visits;public long getId() { return id; }private void setId(long id) { this.id=id; }private Set getVisits() { return visits; }private void setVisits(Set visits) { this.visits=visits; }........
}

以下是Visit类:

package eg;
import java.util.Set;public class Visit {private long id;private String personName;public long getId() { return id; }private void setId(long id) { this.id=id; }private String getPersonName() { return personName; }private void setPersonName(String personName) { this.personName=personName; }........
}

假设一个库具有多次唯一访问,并且每次访问都与一个不同的库相关联,则可以使用如下所示的单向 一对多关联:

<hibernate-mapping><class name="Library"><id name="id"><generator class="sequence"/></id><set name="visits"><key column="library_id" not-null="true"/><one-to-many class="Visit"/></set></class><class name="Visit"><id name="id"><generator class="sequence"/></id><property name="personName"/></class></hibernate-mapping>

我还将提供上述模式的表定义示例:

create table library (id bigint not null primary key )
create table visit(id bigint not nullprimary key,personName varchar(255),library_id bigint not null)
alter table visit add constraint visitfk0 (library_id) references library

那么这张照片怎么了?

当您尝试添加到映射的集合时,可能会出现性能瓶颈。 如您所见,该集合被实现为Set 。 集合保证其所包含元素之间的唯一性。 那么, Hibernate如何知道一个新项目是唯一的以便将其添加到Set中呢? 好吧,不要惊讶; 添加到Set中需要从数据库加载所有可用项。 Hibernate将每一项与新的进行比较,以确保唯一性。 此外,以上是我们无法绕过的标准行为,即使我们由于业务规则而知道新项目是唯一的!

在我们的映射集合中使用List实现也无法解决向其添加项目时的性能瓶颈问题。 尽管列表不保证唯一性,但它们可以保证项目的顺序。 因此,为了在映射的List中保持正确的项目顺序,即使我们将其添加到列表的末尾, Hibernate也必须提取整个集合。

我认为,添加一个新的“ 访问 图书馆”的路很长,您不同意吗?

此外,上面的示例在开发中非常有效,因为我们只有几次访问。 在每个库可能有数百万次访问的生产环境中,请想象一下,当您尝试增加一个库时会降低性能!

为了克服上述性能问题,我们可以将集合映射为Bag ,这只是一个常规集合,没有顺序或唯一性保证,但是在这样做之前,请考虑以下我的最后一点。

当您从集合中删除对象或向集合中添加对象时,集合所有者的版本号会增加。 因此,当同时进行访问创建时,在Library对象上存在人为的乐观锁定异常的高风险。 我们将乐观的锁定异常描述为“人造的”,因为它们发生在集合所有者对象( Library )上,当我们从Visits集合中添加/删除项目时,我们不觉得我们正在编辑(但是我们正在!)。

我要指出的是,相同的规则适用于多对多关联类型。

那么解决方案是什么?

解决方案很简单,从所有者( Library )对象中删除映射的集合 ,然后“手动”执行Visit项目的插入和删除。 提议的解决方案通过以下方式影响使用:

  1. 要将访问添加到库,我们必须创建一个新的“ 访问”项,将其与“ 库”项相关联,并将其显式保存在数据库中。
  2. 要从图书馆中删除访问 ,我们必须搜索“访问”表,找到我们需要的确切记录并将其删除。
  3. 使用建议的解决方案,不支持级联。 要删除资料库,您需要先删除(取消关联)其所有访问记录。

为了保持环境整洁有序,您可以通过实现一个助手方法将“访问”伪集合恢复到Library对象,该方法将查询数据库并返回与特定Library相关的所有Visit对象。 此外,您可以在Visit项目中实现几个帮助程序方法,这些方法将执行实际的访问记录插入和删除操作。

下面,我们提供Library类, Visit类和Hibernate映射的更新版本,以便符合我们提出的解决方案:

首先更新的类:

package eg;
import java.util.Set;public class Library {private long id;public long getId() { return id; }private void setId(long id) { this.id=id; }public Set getVisits() { // TODO : return select * from visit where visit.library_id=this.id}........
}

如您所见,我们删除了映射的集合,并引入了方法“ getVisits() ”,该方法应用于返回特定Library实例的所有Visit项目(TODO注释为伪代码)。

以下是更新的Visit类:

package eg;
import java.util.Set;public class Visit {private long id;private String personName;private long library_id;public long getId() { return id; }private void setId(long id) { this.id=id; }private String getPersonName() { return personName; }private void setPersonName(String personName) { this.personName=personName; }private long getLibrary_id() { return library_id; }private void setLibrary_id(long library_id) { this. library_id =library_id; }........
}

如您所见,我们已经在Visit对象中添加了“ library_id ”字段,以便能够将其与Library项目相关联。

最后是更新的Hibernate映射:

<hibernate-mapping><class name="Library"><id name="id"><generator class="sequence"/></id></class><class name="Visit"><id name="id"><generator class="sequence"/></id><property name="personName"/><property name="library_id"/></class></hibernate-mapping>

因此,永远不要在Hibernate中使用映射的集合吗?

好吧,说实话,不。您需要检查每个案例,以便决定要做什么。 如果收集的数量较小,则标准方法很好-在多对多关联方案的情况下,双方都是如此。 此外,集合将包含代理,因此在初始化之前,它们将小于实际实例。

编码愉快! 别忘了分享!

贾斯汀

聚苯乙烯

在TheServerSide上对这篇文章进行了相当长的辩论之后,一个或我们的读者Eb Bras提供了Hibernate的“技巧和窍门”的有用列表,让他看看该说些什么:

这是我长期记录的一些Hibernate提示和技巧:

反=“真”
一对多的父子关联中(与另一个实体或用作实体的值类型)尽可能多地使用它。
该属性在集合标签(如“ set”)上设置,表示多对一拥有关联,并负责所有数据库的插入/更新/删除。 它使关联成为孩子的一部分。 它将保存外键的数据库更新,因为它将在插入子代时直接发生。

尤其是在使用“集合”作为映射类型时,它可以提高性能,因为不需要将子级添加到父级集合中,这样可以节省整个集合的负载。 那就是:由于集合映射的性质,添加新子元素时必须始终加载整个集合,因为这是hibernate可以确保新条目不是重复项的唯一方法,这是JRE Set的功能接口。
如果它涉及一个组件集合(=仅包含纯值类型的集合),则inverse = true会被忽略并且没有意义,因为Hibernate对对象具有完全控制权,并将选择执行其操作的最佳方法。
如果涉及分离的DTO对象(不包含任何Hibernate对象),则Hibernate将删除所有值类型子对象,然后插入它们,因为它不知道哪个对象是新对象或存在对象,因为它已完全分离。 Hibernate将其视为新集合。

懒惰的Set.getChilds()是邪恶的
使用getChilds()会返回一个Set并会延迟加载所有子项,请务必小心。
当您只想添加或删除孩子时,请勿使用此功能

始终实现equals / hashcode
确保始终对Hibernate管理的每个对象实施equals / hashcode,即使它看起来并不重要。 对于值类型对象也是如此。
如果对象不包含作为equals / hashcode候选者的属性,请使用代理密钥,例如,由UUID组成。 Hibernate使用equals / hashcode找出数据库中是否已经存在对象。 如果它涉及到一个现有对象,但Hibernate认为它是一个新对象,因为equals / hashcode没有正确实现,则Hibernate将执行插入操作,并可能删除旧值。 特别是对于Set中的值类型而言,这一点很重要,必须进行测试,因为它可以节省数据库流量。 想法:您正在给Hibernate提供更多的知识,以便它可以用来优化他的动作。

使用版本
始终将version属性与实体或用作实体的值类型一起使用。
由于Hibernate使用此信息来发现它是否涉及新对象或现有对象,因此这将减少数据库流量。 如果不存在此属性,则必须命中数据库以查找是否涉及新对象或现有对象。

渴望获取
默认情况下,非延迟集合(子项)是通过额外选择查询加载的,该查询仅在从数据库加载父项之后才执行。
通过启用热切获取,可以通过加载集合映射标签上的属性“ fetch = join”来完成与加载父项相同的查询。 如果启用,则通过左外部联接加载子项。 测试这是否可以提高性能。 如果发生许多联接,或者如果它涉及具有许多列的表,则性能将变差而不是变好。

在值类型子对象中使用代理键
Hibernate将在由所有非空列组成的父子关系的值类型子项中构造主键。 这可能会导致奇怪的主键组合,尤其是在涉及日期列时。 日期列不应该是主键的一部分,因为它的毫秒部分将导致几乎绝不相同的主键。 这将导致奇怪的数据库性能,并且可能导致性能下降。
为了改善这一点,我们在所有子值类型对象中使用代理键,这是唯一的非null属性。 然后,Hibernate将构造一个由外键和代理键组成的主键,该主键是逻辑上的且性能良好。 请注意,代理键仅用于数据库优化,并且不需要在可能包含业务逻辑的equals / hashcode中使用。

相关文章 :
  • Java最佳实践–高性能序列化
  • Java最佳实践– Vector vs ArrayList vs HashSet
  • Java最佳实践–字符串性能和精确字符串匹配
  • Java最佳实践–队列之战和链接的ConcurrentHashMap
  • Java最佳实践– Char到Byte和Byte到Char的转换
  • 如何在不到1ms的延迟内完成100K TPS
  • 提升您的Hibernate引擎
  • Cajo,用Java完成分布式计算的最简单方法

翻译自: https://www.javacodegeeks.com/2011/02/hibernate-mapped-collections.html

hibernate 映射

hibernate 映射_Hibernate映射集合性能问题相关推荐

  1. Hibernate映射集合性能问题

    首先,这篇文章的灵感来自于Burt Beckwith在2011年1月27日于SpringOne 2GX上发表的有关高级GORM –性能,定制和监控的演讲 . 简而言之, Burt Beckwith讨论 ...

  2. (转)Hibernate框架基础——映射集合属性

    http://blog.csdn.net/yerenyuan_pku/article/details/52745486 集合映射 集合属性大致有两种: 单纯的集合属性,如像List.Set或数组等集合 ...

  3. hibernate mysql 映射_hibernate与mysql映射类型对应表与mysql导入导出

    http://blog.sina.com.cn/s/blog_5f240fc40100etlt.html 一.记录下hibernate mysql映射类型对应表: 1.常规Hibernate 映射 i ...

  4. hibernate注释映射_Hibernate一对一映射示例注释

    hibernate注释映射 Today we will look into One to One Mapping in Hibernate. We will look into Hibernate O ...

  5. hibernate中的映射文件xxx.hbm.xml详解总结

    一.Hibernate映射文件的作用: Hibernate映射文件是Hibernate与数据库进行持久化的桥梁 二,Hibernate映射文件主要内容:     (1).映射内容的定义: Hibern ...

  6. 初识Hibernate之关联映射(一)

    上篇文章我们对持久化对象进行的学习,了解了它的三种不同的状态并通过它完成对数据库的映射操作.但这都是基于单张表的操作,如果两张或者两张以上的表之间存在某种关联,我们又该如何利用持久化对象进行操作呢?本 ...

  7. 4.Hibernate O/R 映射

    O/R 映射 目前为止我们已经通过应用 Hibernate 见识过十分基础的 O/R 映射了,但是还有三个更加重要的有关映射的话题需要我们更详细的探讨.这三个话题是集合的映射,实体类之间的关联映射以及 ...

  8. Hibernate 实体关联关系映射----总结

    http://lavasoft.blog.51cto.com/62575/39398 Hibernate 实体关联关系映射----总结 花了三天的业余时间,终于写完了Hibernate关联关系映射的所 ...

  9. Hibernate多对多映射 - 连接表

    Hibernate多对多映射 - 连接表 今天我们将使用XML和注释配置来研究Hibernate多对多映射.之前我们看过如何在Hibernate中实现One To One和One To Many映射. ...

最新文章

  1. layui上传报错会有哪些原因_数据丢失如何恢复?哪些原因会导致数据丢失
  2. 社会保险省内转移需要什么手续或过程?
  3. 从 保龄球得分计算方法 浅析 深度学习
  4. c++中algorithm头文件、STL库简介及使用说明
  5. 人工智能之基于face_recognition的人脸检测与识别
  6. 2016经典微小说:《轮回》
  7. python fortran混合编程_python调用fortran模块
  8. Extjs6(六)——增删查改之查询
  9. IntelliJ IDEA 15,16 win 7 64位安装包以及注册码 百度云盘
  10. 小孔怎么用_奶粉罐我再也不扔了,在盖子上打几个孔放床边,全家人都抢着用...
  11. 数据结构编程题及解析c语言版,数据结构习题集答案(C语言版).pdf_c语言数据结构题目,c语言数据结构答案-C/C++文档类资源...
  12. python去重txt文本_Python文本去重
  13. -Dominant Character
  14. 使用阿尔卑斯山法进行高效时间管理
  15. 传奇人形怪爆率怎么设置?人形怪增加教程
  16. 关于js导入Excel时,Excel的(年/月/日)日期是五位数字的问题。以及对Excel日期存在的错误的分析和处理。
  17. 【日成海外营销】如何利用TikTok进行红人营销?
  18. 凸函数的梯度的单调性 (Monotonicity of gradient)
  19. 学计算机南昌哪个中专比较好,南昌中专计算机主要学什么
  20. centos 6.5 编译安装了 Nginx1.6.0+MySQL5.6.19+PHP5.5.14

热门文章

  1. 调用阿里云接口实现短信消息的发送源码——CSDN博客
  2. Servlet 登录时数据校验
  3. 2的负x次幂图像_数学| NO.2,3 函数 T15
  4. docker 买了腾讯服务器后的学习
  5. hbase 单机连接hadoop_Hadoop、Hbase单机环境安装
  6. python菱形画法解释_用Python画棱形
  7. Access restriction: The type 'BASE64Encoder' is not API 的解决方法
  8. gradle 构建 Smack 报错:Can't find android.jar for 8 API. + steps for building android platform
  9. tomcat(17)启动tomcat
  10. 使用MRUnit,Mockito和PowerMock进行Hadoop MapReduce作业的单元测试