Hibernate Criteria 查询 出现重复实体
Posted 滕哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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取消关联关系为例:
- 取消Role和RoleResourcePermission的OneToMany关联
- 查询Role实体直接返回Role实体集合
- 在使用Role实体时,如果需要用到RoleResourcePermission,则根据roleId自行获取RoleResourcePermission集合
- 如果不需要使用RoleResourcePermission的话,则不需要进行查询
以上方式因为每次查询都是无关联的实体,所以也就不需要Distinct Entity操作了,即使使用Criteria元查询也是可以使用maxResults进行分页的,由于多端实体只在需要的时候才会加载,所以也算是懒加载的一种方式
以上是关于Hibernate Criteria 查询 出现重复实体的主要内容,如果未能解决你的问题,请参考以下文章
hibernate hql查询 与Criteria 查询语句区别和效率