由于Hibernate的强大,我们对数据库的操作也省心了不少,但是hibernate自动生成的一系列sql,也许并不是如我们所想象的那样,所以,我们又多了一些本来不要操心的事情。比如在一对多的查询中,就有可能存在查询记录重复的问题。
有如下两个对象:文章和关键字。它们之间的关系,很明显,是一对多的关系,一个文章可以有很多的关键字。
假设有文章atricleA、articleB,articleA有关键字keyword1、keyword2,articleB有关键字keyword3、keyword4。
我们现在想查询含有关键字keyword1或者keyword3的所有文章列表,正确的结果应该是articleA和articleB两条记录。然而,如果使用hibernate不当,有可能你得到的是articleA、articleA、articleB、articleB四条记录,其中两条是重复的。
这是怎么发生的呢?
如果我们这样使用hibernate来实现这个查询:
StringBuffer queryString = new StringBuffer();
queryString.append("from ArticleData where keyword=? or keyword=?");
String[] param = new String[]{"keyword1","keyword3"};
Query query = session.createQuery(queryString );
query.list();
看看hibernate给我们生成的sql语句:
select article_table_.*
from articletable article_table_,keywordtable keyword_table1_ ,keywordtable keyword_table2_
where article_table_.id=keyword_table1_.articleid and article_table_.id=keyword_table2_.articleid
and (keyword_table1_.name='keyword1' or keyword_table2_.name='keyword3')
根据这个sql,我们可以得出,满足where约束的有如下几个组合:
articleA keyword1 keyword1
articleA keyword1 keyword2
aritcleB keyword3 keyword3
articleB keyword3 keyword4
正是我们之前所说得到的错误结果。
仔细分析这个sql,其实问题就出在hibernate生成sql的时候,对同一个表keywordtable查询了两次(在from中出现两次),因此就有了组合的可能性,可以想见,如果再多几个需要查询的关键字,同一个记录重复的次数会更多。
其实,要正确的破解这个问题,我们可以自己写sql语句,使用hibernate同样支持的原生sql查询,不使用hibernate的hql查询。
hibernate在给我们带来很多便利性的同时,也给我们多多少少带来了一些麻烦,而这些问题的定位成本可能也会很高。要使用好工具,就要知道工具的优缺点,尤其是缺点要有足够的风险控制。
革命尚未成功,同志仍需努力!