关于Hibernate中对集合类型的映射
发布日期:2021-06-30 16:53:04 浏览次数:2 分类:技术文章

本文共 4602 字,大约阅读时间需要 15 分钟。

Each interface has a matching implementation

supported by Hibernate, and it’s important that you use the right combination.

 

先说一个 @JoinColumn的问题。

这个注解是用来说明关联列的信息的。

按自然的做法是:多在Many端上描述这些信息,因为从DB表上来看,关联列者是many端的表上外键列。

但是,如果是单向的one-to-many时就只能在one上映射了。这时候看起来会有些让人迷惑。

 

再补补集合中的一些知识吧,有些确实生疏了:

关于Set下面的几个具体实际的对比:

  1.  *    HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放;   
  2.  *    LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代;   
  3.  *    TreeSet:提供一个使用树结构存储Set接口的实现,通过提供元素比较器,使得集合在插入过程中直接有序。

LinkedHashSet没有实现什么特殊接口用以表明它是有序的。

 

1.关于Set的映射

在基于xml配制的情况下如果你的只是声明一个普通的set,那个在实例化对象时,hibernate会生成HashSet。

而如果在set的配制中加入order-by,hibernate就会生成LinkedHashSet了!这样就是一个有序的集合了。

 

关于Set的排序和Hibernate如何生成Set实例的问题:

 

内存排序:

Set映射有两种排序方式,一是使用映射文件中的sort属性,一般需要自己实现一个java.util.Comparator,sort属性

指定自己实现的比较类,hibernate返回给客户的实际是Set的TreeSet实现,将该比较类作为treeSet的比较器,这种

排序是在内存中进行的,可以在比较器中按实体类的某个字段排序或实现更复杂的排序方法,非常灵活,但是要自己实

现比较器,麻烦一些。

 

以下是两个例子:

 

<set name="aliases" table="person_aliases" sort="natural" >

<key column="person"/>
<element column="name" type="string"/>
</set>

 

<map name="holidays" sort="my.custom.HolidayComparator" >

<key column="year_id"/>
<map-key column="hol_name" type="string"/>
<element column="hol_date" type="date"/>
</map>

 

sort 属性中允许的值包括 unsorted,natural 和某个实现了 java.util.Comparator 的类的名称。

 

数据库排序:

另一种方法是使用映射中的order-by属性,可以指定表中的一个排序字段,排序是在数据库中进行的,hibernate返回

LinkedHashSet实现,可以保持对象的前后次序。

 

以下又是两个例子

<set name="aliases" table="person_aliases" order-by="lower(name) asc" >

<key column="person"/>
<element column="name" type="string"/>
</set>
<map name="holidays" order-by="hol_date, hol_name" >
<key column="year_id"/>
<map-key column="hol_name" type="string"/>
<element column="hol_date type="date"/>
</map>
所以参考中说在实体类中定义子集合时不要定义成HashSet,而应该是Set接口,因为它返回的不一定是HashSet。
对于List(Bag映射),可以指定order-by排序字段,并不需要index列。

 

关于List的影射:

首先要强调的是:很多时候,我们的java.util.List可以映射成bag的!

因为大多数时候,我们需要的只是一组从数据库里取出的数据,至于顺序,只能是从数据库中查出时的先后顺序(按ID升序)。在这种需求下,如果要使用set,那么必须要在映射中加入order-by,而如果使用list(xml中的list),那么还需要额外的index-column!所以最好的方案就是用bag.

在基于注解的配制方式时:

如果在List字段上不加@IndexColumn,那么这个List就会被映射成Hibernate里bag

 

 

1、其实hibernate是有提供list映射的, list就是bag类型,bag适合关联的集合类中有排序需求

    在配置list的时候,也有几种方法:指定list-index,这也就要在数据库中对应创建一个字段表示顺序

对于一对多关联当中的List,需要在数据库里面维护一个index列,如果List当中的某个元素被删除,那么Hibernate

连续发送多条update语句,更新后续所有元素的index列,以确保index的连续性(在inverse为false的情况下),如果

你选择自己维护index列,也同样会面临这个问题,甚至更棘手(在inverse为true的情况下),所以List被谨慎的使用在

极其罕见的场合。

    但是,这里所说的要特别慎用list是指的hibernate映射文件中的list类型,而不是实体类中的List类型。映射文件中

用Bag类型,在实体类中是可以对应List的。

 

关于@CollectionOfElements

Hibernate一直强调值对象与实体类之间差异,这在集合类型的映射上体现的极为明显。在映射集合类型的值对象进,使用xml有<element>, 使用注解则有@CollectionOfElements

 

关于@org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)

 

The collection is no longer initialized if you call size(), contains(), or isEmpty().

 org.hibernate.annotations.LazyCollectionOption.EXTRA是较一般lazy loading更加lazy,或者说更加智能的选项,当访问集合的size(), contains(), or isEmpty()时,并不加载整个集合,这对加载大集合来说很适用!

 

使用了@org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA),

集合变得更“聪明”,调用size()时,不会加载集合,打出的sql是:

select

        count(id)
    from
        Thread
    where
        forumId =?
  
没有使用@org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)时,
只要用的size(),就会导致整个集合加载!以是打出的SQL 
select
        threads0_.forumId as forumId4_,
        threads0_.id as id4_,
        threads0_.id as id5_3_,
        threads0_.creationTime as creation2_5_3_,
        threads0_.forumId as forumId5_3_,
        threads0_.modifiedTime as modified3_5_3_,
        threads0_1_.subjectId as subjectId6_3_,
        post1_.id as id4_0_,
        post1_.authorId as authorId4_0_,
        post1_.creationTime as creation2_4_0_,
        post1_.isSubject as isSubject4_0_,
        post1_.messageBody as messageB4_4_0_,
        post1_.modifiedTime as modified5_4_0_,
        post1_.quotedPostId as quotedPo8_4_0_,
        post1_.title as title4_0_,
        user2_.id as id0_1_,
        user2_.accountNonExpired as accountN2_0_1_,
        user2_.accountNonLocked as accountN3_0_1_,
        user2_.credentialsNonExpired as credenti4_0_1_,
        user2_.email as email0_1_,
        user2_.enabled as enabled0_1_,
        user2_.password as password0_1_,
        user2_.username as username0_1_,
        user2_.version as version0_1_,
        post3_.id as id4_2_,
        post3_.authorId as authorId4_2_,
        post3_.creationTime as creation2_4_2_,
        post3_.isSubject as isSubject4_2_,
        post3_.messageBody as messageB4_4_2_,
        post3_.modifiedTime as modified5_4_2_,
        post3_.quotedPostId as quotedPo8_4_2_,
        post3_.title as title4_2_
    from
        Thread threads0_
    left outer join
        Thread_Subject threads0_1_
            on threads0_.id=threads0_1_.threadId
    left outer join
        Post post1_
            on threads0_1_.subjectId=post1_.id
    left outer join
        User user2_
            on post1_.authorId=user2_.id
    left outer join
        Post post3_
            on post1_.quotedPostId=post3_.id
    where
        threads0_.forumId=?

转载地址:https://laurence.blog.csdn.net/article/details/5541817 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:关于为什么单向一对多(one-to-many)要使用关联表的再思考
下一篇:关于有状态类与集群

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年04月20日 08时47分11秒