Hibernate Criteria 查询 出现重复实体

Hibernate Criteria 查询 出现重复实体

Role与RoleResourcePermission是OneToMany关系,通过Hibernate Criteria查询Role对象时,OUT LEFT JOIN导致Role对象重复

思路

Hibernate的关联查询分为查询和实体包装,left join查询出来的结果本身是不重复的,或者说是只有多端实体不重复,但是Hibernate在做完实体包装之后,因为多端实体被包装成集合,导致生成的最终实体是重复的

解决方法

1、使用DISTINCT_ROOT_ENTITY

Criteria criteria = session.createCriteria(Role.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.list();

通过设置根实体级别的排重得到不重复的实体集合,但是这种方式引入了新的问题。

引入的新问题 1

思路中提到,Hibernate的关联查询分两步,先查询后包装,在使用元查询做分页的时候,maxResults在查询时就已确定,而distinct entity是对实体的操作,所以会导致实际查出来的实体数比maxResults的预期要少。所以在使用这种方式进行查询的时候,不推荐使用元查询的maxResults字段进行分页。

2、设置FetchType.LAYZ

    @OneToMany(fetch = FetchType.LAYZ, mappedBy = "role")

将fetch方式改为懒加载,那么在关联查询的时候,多端对象不会被查出来,只会在用到的时候才会进行查询,这就相当于不进行left join查询了,那么得到的结果也是不重复的,但是这种方式也会引入新的问题。

引入的新问题 2

Hibernate的懒加载是session级别的,目的是用来提升性能。当在同一个session下,直接查询Role实体,实体中不包含多端对象,当需要获取多端对象时Hibernate才会从数据库中进行查询;如果在一个session中查询出Role实体,但是在session关闭之后再去获取多端对象的话,Hibernate则会抛出:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.teemo.entity.Role.resourcePermissions, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:563)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:205)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:542)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:133)
    at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:163)

3、取消实体之间的非必要join

取消实体之间的非必要join,只在用到的时候才去查询子实体,这样做的好处是既不影响分页,又提升了查询性能,不好的地方是可能需要多次查询

以Role和RoleResourcePermission取消关联关系为例:

  1. 取消Role和RoleResourcePermission的OneToMany关联
  2. 查询Role实体直接返回Role实体集合
  3. 在使用Role实体时,如果需要用到RoleResourcePermission,则根据roleId自行获取RoleResourcePermission集合
  4. 如果不需要使用RoleResourcePermission的话,则不需要进行查询

以上方式因为每次查询都是无关联的实体,所以也就不需要Distinct Entity操作了,即使使用Criteria元查询也是可以使用maxResults进行分页的,由于多端实体只在需要的时候才会加载,所以也算是懒加载的一种方式


版权声明:本文为u011404265原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。