hibernate 映射_Hibernate映射集合性能问题

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 映射

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

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

相关文章

SEL selector (二)

SEL消息机制工作原理是什么 引用下面文章&#xff1a; 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有一个 isa 的成员变量[公共继承].而该 isa 变量指向该对象的类(图3.15)[类在Objective-C中…

Ext grid 根据行号获取行数据

var storeExt.getCmp(grid_id).store;// var storerowstore.getAt(row_num);//行数据 var phonenumberstorerow.get(phonenumber);//列信息 //------------------------------------------------------------------------- var dataExt.getCmp(grid_id).store.data; var d…

mobile cpu上禁用alpha test的相关总结

因为&#xff0c;每家芯片的特性不同&#xff0c;根据向framebuffer写法的不同&#xff0c;分为tile-based的mobile cpu&#xff0c;如ImgTec PowerVR&#xff0c;ARM Mali&#xff0c;一部分老版本Qualcomm Adreno。还有标准的direct&#xff08;immediate&#xff09;的mobil…

学习笔记_jquery(js)遍历页面标签

$(#selectTable tr).each(function(i){ // 遍历 tr $(this).children(td).each(function(j){ // 遍历td var id $(this).context.id; }); }); //---------------------- $("input[namename1]").each(function(){ //遍历name…

简易分享功能(非第三方)

在做一个新项目时&#xff0c;需要一个新浪和微信的分享功能&#xff0c;起初看到这个需求&#xff0c;感觉没有什么&#xff0c;直接使用第三方比较成熟的分享组件就可以的&#xff0c;比如&#xff1a;jiathis、百度分享组件&#xff0c;这些都可以很轻松并且方便的完成所需要…

达梦定时迁移数据

1. 生成迁移源代码 1.1 启动DM迁移工具&#xff08;bin/dts.exe&#xff09; 1.2 右击迁移管理空白处 -> 新建工程 1.3 展开工程 -> 右击迁移&#xff0c;新建迁移 -> 输入迁移名称&#xff0c;确认 1.4 右击迁移名称&#xff0c;打开 -> 输入源数据库连接信息&…

JSP教程–最终指南

编者注&#xff1a; JavaServer Pages&#xff08;JSP&#xff09;技术使您可以轻松创建同时包含静态和动态组件的Web内容。 JSP技术提供了Java Servlet技术的所有动态功能&#xff0c;但提供了一种更自然的方法来创建静态内容。 JSP技术的主要功能包括用于开发JSP页面的语言&…

CRC校验(转)

CRC即循环冗余校验码&#xff08;Cyclic Redundancy Check[1] &#xff09;&#xff1a;是数据通信领域中最常用的一种差错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查&#xff08;CRC&#xff09;是一种数据传输检错功能&#xff0c;对数据…

tongweb6数据源使用中时常报空异常处理方式

1.在tongweb控制台 -> jdbc配置中设置数据源参数 1.1 勾选空闲超时&#xff0c;时间默认 1.2 勾选泄露超时时间 &#xff0c;时间为半天&#xff08;14400&#xff09; 1.3 勾选连接有效性检查、创建连接验证、获取连接验证、归还连接验证 图中设置泄露超时时间为900…

Ios tab Bar 使用方法

http://blog.sina.com.cn/s/blog_63578f140100w56m.html UITabBar* tabBar [[UITabBar alloc] initWithFrame:CGRectMake(40,0.0,240,30)]; [mainView addSubview:tabBar]; [tabBar release]; UITabBarItem *tabBarItem1 [[UITabBarItem alloc] initWithTitle:"排队人数…

spring smtp_使用Spring使用Java发送电子邮件– GMail SMTP服务器示例

spring smtp对于使用Java发送电子邮件&#xff0c; JavaMail API是标准解决方案。 如官方网页所述&#xff0c;“ JavaMail API提供了独立于平台和协议的框架来构建邮件和消息传递应用程序”。 必需的类包含在JavaEE平台中&#xff0c;但是要在独立的JavaSE应用程序中使用它&am…

关闭uboot MMU 会导致android2.3 S5pv210 系统不稳定?!why

问题描述在uboot里面屏蔽了MMU 使能//#define CONFIG_ENABLE_MMU就导致android 2.3 在S5pv210 上不稳定了&#xff0c;如果没屏蔽就稳定很多&#xff0c;why&#xff1f;&#xff01;坑爹的人啊&#xff0c;问了一些做了几年linux和android的人说没影响的&#xff0c;啥玩意啊&…

Java 9中的5个功能将改变您开发软件的方式(还有2个不会)

有望在Java 9中发布的最令人兴奋的功能是什么&#xff1f; 不要对Java 9的相对沉默近来分散注意力。JDK提交者正在努力准备下一个版本&#xff0c;该版本预计将在2015年12月完成&#xff0c;而功能将在几个月后完成 。此后&#xff0c;它将通过严格的测试和错误修复了将其计划…

eclipse远程tomcat javaweb debug样例(windows)

1.tomcat配置可被远程debug端口参数 catalina.bat 中添加 set CATALINA_OPTS-Xdebug -agentlib:jdwptransportdt_socket,servery,suspendn,address8000 导出项目war包到tomcat/webapps/目录下 切换到tomcat/bin目录下 双击startup.bat启动运行项目 2.eclipse中启动远程debug…

总账分录追溯发票或者付款

--总账分录追溯发票 SELECT DISTINCT AIA.*FROM AP_AE_HEADERS_ALL AAH, --帐户分录头表AP_AE_LINES_ALL AAL, --账户分录行表&#xff0c;每一个会计事件都会在此表中产生会计分录GL_JE_BATCHES GJB,GL_JE_HEADERS GJH,GL_JE_LINES GJL,AP_INVOICES_ALL …

mysqlDM判断字符串中是否存在非中文

MYSQL判断字符串是否全中文 正则表达式匹配[一-龥]中文字符[ a-zA-Z]英文字母[ 0-9]数字[ぁ-ゞァ-ヾ]日文字符1.查询存在非中文的记录 &#xff1a;select * from tablename where columnname REGEXP [^一-龥]; 2.查询存在中文的记录&#xff1a;select * from columnname wh…

ASP.NET MVC的ContentResult

ASP.NET MVC的ContentResult返回简单的纯文本内容&#xff0c;可通过ContentType属性指定应答文档类型&#xff0c;通过ContentEncoding属性指定应答文档的字符编码。一个例子来演习&#xff0c;自定义一个RwResult&#xff0c;它继承ContentResult&#xff0c;为视图象ASP.NET…

windows搜索指定目录下包含某个字符串的文件

1.打开cmd窗口 &#xff1a;winr 快捷键-> 输入cmd 回车 2.切换到被搜索的文件夹&#xff08;E:\shgwy文档\日常\更新\20220808&#xff09;下 如输入&#xff1a; cd E:\shgwy文档\日常\更新\20220808 e: 3.输入搜索命令 c:\Windows\System32\findstr.exe /s /i "wa…

IIS7日志文件位置

准备统计下页面访问量 查找IIS日志,发现在以前IIS6日志的位置&#xff0c;竟然木有找到日志... 查看下IIS设置&#xff0c;发现IIS7和6的默认日志位置不一样额... IIS 6 Log files location IIS 6中日志文件的位置 %windir%\System32\LogFiles IIS 7 Log files location IIS的日…

编写下载服务器。 第二部分:标头:Last-Modified,ETag和If-None-Match

客户端缓存是万维网的基础之一。 服务器应告知客户端资源的有效性&#xff0c;客户端应尽可能快地对其进行缓存。 如我们所见&#xff0c;如果不缓存Web&#xff0c;将会非常慢。 只需在任何网站上Ctrl F5并将其与普通F5进行比较-后者就会更快&#xff0c;因为它使用了已缓存的…