理解Hibernate集合性能技术

开发 后端
Hibernate集合性能(Understanding Collection performancee)技术的分类、Lists, maps 和sets用于更新效率最高、Bag和list是反向集合类中效率最高的。

本段中,我们将着重讲述Hibernate集合性能(Understanding Collection performance)集合在运行时的事宜。包括Hibernate集合性能(Understanding Collection performancee)技术的分类、Lists, maps 和sets用于更新效率最高、Bag和list是反向集合类中效率最高的。
 
1.Hibernate集合性能分类(Taxonomy),Hibernate定义了三种基本类型的集合:

◆值数据集合

◆一对多关联

◆多对多关联

这个分类是区分了不同的表和外键关系类型,但是它没有告诉我们关系模型的所有内容。 要完全理解他们的关系结构和性能特点,我们必须同时考虑“用于Hibernate更新或删除集合行数据的主键的结构”。 因此得到了如下的分类:

◆有序集合类

◆集合(sets)

◆包(bags)

所有的有序集合类(maps, lists, arrays)都拥有一个由组成的主键。 这种情况下集合类的更新是非常高效的——主键已经被有效的索引,因此当Hibernate试图更新或删除一行时,可以迅速找到该行数据。

集合(sets)的主键由和其他元素字段构成。 对于有些元素类型来说,这很低效,特别是组合元素或者大文本、大二进制字段; 数据库可能无法有效的对复杂的主键进行索引。 另一方面,对于一对多、多对多关联,特别是合成的标识符来说,集合也可以达到同样的高效性能。( 附注:如果你希望SchemaExport为你的创建主键, 你必须把所有的字段都声明为not-null="true"。)

映射定义了代理键,因此它总是可以很高效的被更新。事实上, 拥有着最好的性能表现。

Bag是最差的。因为bag允许重复的元素值,也没有索引字段,因此不可能定义主键。 Hibernate无法判断出重复的行。当这种集合被更改时,Hibernate将会先完整地移除 (通过一个(in a single DELETE))整个集合,然后再重新创建整个集合。 因此Bag是非常低效的。

注意:对于一对多关联来说,“主键”很可能并不是数据库表的物理主键。 但就算在此情况下,上面的分类仍然是有用的。(它仍然反映了Hibernate在集合的各数据行中是如何进行“定位”的。)

2.  Lists, maps 和sets用于更新效率最高

根据我们上面的讨论,显然有序集合类型和大多数set都可以在增加、删除、修改元素中拥有最好的性能。

可论证的是对于多对多关联、值数据集合而言,有序集合类比集合(set)有一个好处。因为Set的内在结构, 如果“改变”了一个元素,Hibernate并不会更新(UPDATE)这一行。 对于Set来说,只有在插入(INSERT)和删除(DELETE) 操作时“改变”才有效。再次强调:这段讨论对“一对多关联”并不适用。

注意到数组无法延迟载入,我们可以得出结论,list, map和idbags是最高效的(非反向)集合类型,set则紧随其后。 在Hibernate中,set应该时最通用的集合类型,这时因为“set”的语义在关系模型中是最自然的。

但是,在设计良好的Hibernate领域模型中,我们通常可以看到更多的集合事实上是带有inverse="true" 的一对多的关联。对于这些关联,更新操作将会在多对一的这一端进行处理。因此对于此类情况,无需考虑其集合的更新性能。

3.  Bag和list是反向集合类中效率最高的

在把bag扔进水沟之前,你必须了解,在一种情况下,bag的性能(包括list)要比set高得多: 对于指明了inverse="true"的集合类(比如说,标准的双向的一对多关联), 我们可以在未初始化(fetch)包元素的情况下直接向bag或list添加新元素! 这是因为Collection.add())或者Collection.addAll() 方法 对bag或者List总是返回true(这点与与Set不同)。因此对于下面的相同代码来说,速度会快得多。

  1. Parent p = (Parent) sess.load(Parent.class, id);  
  2.     Child c = new Child();  
  3.     c.setParent(p);  
  4.     p.getChildren().add(c);  //no need to fetch the collection!  
  5.     sess.flush(); 

4.  一次性删除(One shot delete)

偶尔的,逐个删除集合类中的元素是相当低效的。Hibernate并没那么笨, 如果你想要把整个集合都删除(比如说调用list.clear()),Hibernate只需要一个DELETE就搞定了。

假设我们在一个长度为20的集合类中新增加了一个元素,然后再删除两个。 Hibernate会安排一条INSERT语句和两条DELETE语句(除非集合类是一个bag)。 这当然是显而易见的。

但是,假设我们删除了18个数据,只剩下2个,然后新增3个。则有两种处理方式:

逐一的删除这18个数据,再新增三个;

删除整个集合类(只用一句DELETE语句),然后增加5个数据。

Hibernate还没那么聪明,知道第二种选择可能会比较快。 (也许让Hibernate不这么聪明也是好事,否则可能会引发意外的“数据库触发器”之类的问题。)

幸运的是,你可以强制使用第二种策略。你需要取消原来的整个集合类(解除其引用), 然后再返回一个新的实例化的集合类,只包含需要的元素。有些时候这是非常有用的。

显然,一次性删除并不适用于被映射为inverse="true"的集合。

【编辑推荐】

  1. 简述Hibernate中加载并存储对象
  2. Hibernate传播性持久化攻略
  3. 深入了解Hibernate自动状态检测
  4. 简单学会Hibernate对象持久化
  5. 分析Hibernate自增主键
责任编辑:仲衡 来源: javanb
相关推荐

2012-02-03 11:17:33

HibernateJava

2009-06-16 16:10:59

Hibernate性能

2009-09-23 14:23:51

Hibernate主键

2009-09-24 09:44:32

Hibernate j

2009-09-25 09:46:02

Hibernate高级

2009-09-22 12:45:00

Hibernate性能

2009-09-22 17:41:07

Hibernate性能

2009-06-06 15:37:22

Hibernate性能

2009-06-16 16:39:49

Hibernate性能

2012-06-02 00:55:44

HibernateflushJava

2009-06-18 10:29:24

Hibernate I

2009-09-25 09:14:35

Hibernate日志

2009-09-22 15:22:08

Hibernate性能

2009-09-22 17:25:41

优化Hibernate

2009-09-25 13:10:15

Hibernate性能

2009-09-23 08:56:18

Hibernate cHibernate i

2009-09-28 09:40:28

Hibernate集合延迟加载

2009-09-23 11:37:31

Hibernate S

2009-09-23 12:48:54

Hibernate I

2009-09-24 13:45:53

Hibernate性能
点赞
收藏

51CTO技术栈公众号