在hibernate里用Projection里的一个有关问题及其解决
在<想看Hibernate生成的SQL语句?>里,我列出怎么来看Hibernate生成sql的方法, 在末尾留了一个小尾巴,今天把它补上.
程序中的实际场景是这样的, 一个Model类里有contractBw,nodeType,subCompany,overBw等属性, 现在要对contractBw和overBw有三次汇总求和并显示记录条数,分别是按contractBw,nodeType,subCompany来 group by.
这样在程序中用Projections来做, 有了以下的代码:
projList.add(Projections.rowCount(),"rowCount");
projList.add(Projections.sum("overBw"),"overBw");
projList.add(Projections.groupProperty(groupItem),groupItem);
queryCirteria.setProjection(projList);
queryCirteria.setResultTransformer(new AliasToEntityMapResultTransformer());
这里的参数groupItem上层代码可以设定为"contractBw","nodeType", "subCompany",从而达到三次求和可以共用这上面的代码.
这样写,猛一看没什么问题, 也能跑的通.
但看页面上的数据时发现问题了, 数据不对劲: 如果一个contractBw为2000M的记录有2条,sum出来和应该是4000M才对,可显示是2000M, 这是怎么回事?
是什么地方出问题了? 从哪下手? 这样的问题在网上也没法, 只能自己硬着头皮解决了. 幸好自己的IDE里配置了debug功能,于是就跟踪源码了, 胡乱地设置了几个断点后,没发现有什么价值的信息,不过看IDE里方法的调用栈,发现有这么一个preprocessSQL, 难道是与生成的SQL有关? 嘿嘿... 要是真是那样就好了, 可以用hibernate生成的代码在数据库里运行下,看看结果怎样.
于是在preprocessSQL方法sql = applyLocks( sql, parameters.getLockModes(), dialect );一句处设置了断点. 一运行,还真能看到生成的SQL, 拷到数据库里一执行, 乖乖, 没问题.....
电光火石间, 我意识到了:
projList.add(Projections.groupProperty(groupItem),groupItem);
这里出问题了.这里得另起名字,于是改成了
projList.add(Projections.groupProperty(groupItem),groupItem+"item");
现在想想,那种感觉太奇妙了!从看到hibernate生成的sql在数据库里执行结果显示出来到意识到问题的根源,感觉这期间不超过一秒钟!
这样改了后,再启动,没问题了:2000M的记录有2条,sum出来和也是4000M!
现在回过来头来看看, 是什么促使自己能在这么短的时间能发现并改正程序中的问题呢?在IDE中设置断点用hibernate生成的sql在数据库中执行起到了关键性的作用. 下一篇中将分析结合hibernate的执行过程分析下为什么这样改是正确的.