hibernate之fetch
1.配置OpenSessionInViewFilter,让Session在View层中保存打开状态,可以随时使用,这看起来是个一劳永逸的办法,但其也带来了一些问题, 至于会有什么样的问题百度会给你答案。
2.在映射实体时把关联属性设置lazy="false",表示该关联关系不进行懒加载,这样该实体关联属性就会一起被查询出来,这种方式有时候是可行的,但最大的问题就是不灵活,一但配置lazy="false",有时候不想该实体关联属性一起被查询出来就无能为力了
3.在hql中提供了一个"fetch"关键字,其字面意义就是"抓取",利用它可以灵活地抓取我们想要查询实体关联属性。例如:查询用户抓取角色:FROM User u LEFT JOIN FETCH u.roles rs WHERE...,如果角色还要抓取限制,则:FROM User u LEFT JOIN FETCH u.roles rs LEFT JOIN FETCH rs.privileges ps WHERE...
FETCH使用起来的确很灵活,但在最近的一次使用中却碰见了一个问题,就是在得到的结果集中可能出现多条相同的记录,这是我们所不想要的
举个例子:
/** 论坛主题 **/ public class Theme { /** 数据库ID **/ private Integer id; /** 标题 **/ private String title; /** 主题内容 **/ private String content; /** 回复 **/ private Set<Reply> replies = new HashSet<Reply>(); //getter... //setter... }
/** 主题回复 **/ public class Reply { /** 数据库id **/ private Integer id; /** 回复内容 **/ private String content; /** 回复所属主题 **/ private Theme theme; //getter... //setter... }
为了简单起见,只是列出了示例属性,getter与setter方法也省略掉了。现在当我们查询Theme的时候要抓取出Reply,这时hql语句为:FROM Theme t LEFT JOIN FETCH t.replies rs WHERE t.id=?,执行查询后得到Query对象,这时你如果调用的是uniqueResult()方法你将得到正确的结果,但是当你调用的是list()方法,你会发现这个结果列表中很可能出现了多条重复的记录,确切的说是该Theme有多少个Reply就会有多少条重复的记录,这时你肯定会说调用uniqueResult()方法不就完了吗?在这种本来就只有一条记录的情况肯定是没有问题的,但有时候我们想返回的就是多条记录呢?比如,根据Theme的title属性进行模糊匹配(不考虑全文索引)的时候,这时hql语句为:FROM Theme t LEFT JOIN FETCH t.replies rs WHERE t.title like ?,我们要返回的就是一个List列表,这时只能调用Query.list()方法,这样势必会出现多条重复记录。那么如何解决呢?
1.加上DISTINCT关键字,hql变为:FROM DISTINCT Theme t LEFT JOIN FETCH t.replies rs WHERE t.title like ?,这样一般情况下 能返回确定的结果,但有时候也不行。例如,在Oracle中当有字段为clob,blob类型时就行不通过了,因为数据根本不知道对于clob,blob类型 的数据到底是不是相等,其它数据库就没有试过了,我估计也不行。所以DISTINCT关键字也不是万能的。
2.在返回含有相同记录的List中,手工进行排除掉相同的记录,但这会增加额外的工作量,大家肯定也不愿干。
3.在调用list()方法之前,调用query.setFirstIndex(0).setMaxResult(Integer.MAX_VALUE);这样一个分页语句肯定是获取出了全部的记录 这样虽然能获取出正确的结果,但你会发现和没有设置分页执行的SQL语句是一样的,这就说明在这种情况下hibernate是先获取出了全部符合 条件的记录然后再进行分页的。当你不需要分页的情况下执行是没有问题的,如果你又想分页又想级联抓取就会获取出不必要的记录,因为 它是在内存中分页的。而且这样hibernate还会报一个警告:WARNING: firstResult/maxResults specified with collection fetch; applying in memory! 大致意思说的就是在内存中进行分页,这样肯定有性能方面的问题,这个问题可以参看:点击打开链接
在相比之下,个人觉得还是第3种解决方案是最合适的(如果还有更好的解决方案请不吝赐教),因为只要不进行分页都是可以满足要求的,如果要进行分页只能不进行级联抓取了,要获取实体关联属性另外写查询语句。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。