跟Hibernate(十五):用Hibernate求记录总数的一个怪胎 里描述的问题相关.
项目中一个需求要得到满足条件记录的总数,起初想到的是DetachedCriteria里设置setProjection (Projections.projectionList().add(Projections.rowCount(), "rowCount"))后, 再以setResultTransformer(DetachedCriteria.ALIAS_TO_ENTITY_MAP)方式得到一个Map结果, 再以rowCount为key来取值. 但在执行getHibernateTemplate().findByCriteria(d)时程序卡要那不走了.
试了几次后,没发现什么好的方法,不得以就采用了Hibernate(十五):用Hibernate求记录总数的一个怪胎 里说的那个不伦不类的list后再size来求值. 这样任务算做完了,回过头再看是什么原因造成了上面所说的程序卡了.
尝试点1: DetachedCriteria子查询与DetachedCriteria.ALIAS_TO_ENTITY_MAP时出问题了. 代码如下所示:
DetachedCriteria hasInfoForCurrentDeptQuery = DetachedCriteria.forClass(ContractTrade.class); hasInfoForCurrentDeptQuery.setProjection(Projections.projectionList() .add(Projections.rowCount(), "rowCount")); //设置子查询 DetachedCriteria hasImportedQuery = DetachedCriteria.forClass(ContractOtherLink.class); hasImportedQuery.setProjection(Property.forName("linkContId")); hasInfoForCurrentDeptQuery.add(Property.forName("contractTradeId").notIn(hasImportedQuery)); hasInfoForCurrentDeptQuery.setResultTransformer(DetachedCriteria.ALIAS_TO_ENTITY_MAP); Map result = (Map)getHibernateTemplate() .findByCriteria(hasInfoForCurrentDeptQuery).get(0); // --(1)
这样的代码执行在(1)处时整个程序卡在那不走了.怀疑是DetachedCriteria子查询与DetachedCriteria.ALIAS_TO_ENTITY_MAP配合上出了问题, 于是看Hibernate生成的SQL(生成sql: select count(*) as y0_ from UPLOAD_CONTRACT_ITRADE_VIEW this_ where this_.DEPT_ID=24 and this_.CONTRACT_ID not in (select this0__.LINK_CONT_ID as y0_ from CONTRACT_OTHER_LINK this0__) ), 再在Toad里执行是,没问题. 出结果了.
尝试点2: 用Java+hibernate程序来试DetachedCriteria与DetachedCriteria.ALIAS_TO_ENTITY_MAP 配合. 尝试点1是从最后生成的SQL来看两者的配合是否成功的, 看上面生成的SQL发现外围查询(select count (*) as y0_ )与子查询(select this0__.LINK_CONT_ID as y0_ )用的别名都是y0_, 会不会最终在Hibernate对结果组装时由于别名相同出问题了. 于是再用真实的Java程序再试下, 实验代码如下:
Session session = sessionFactory.getCurrentSession(); Transaction t = session.beginTransaction(); DetachedCriteria queryCirteriaOuter = DetachedCriteria.forClass(DataDict.class); queryCirteriaOuter.setProjection(Projections.projectionList() .add(Projections.rowCount(), "rowCount")); DetachedCriteria queryCirteriaInner= DetachedCriteria.forClass(DataDictLink.class); queryCirteriaInner.add(Restrictions.like("tableName", "S_CONTACT")); queryCirteriaInner.setProjection(Property.forName("columnName")); queryCirteriaOuter.add(Property.forName("listType").in(queryCirteriaInner)); queryCirteriaOuter.setResultTransformer(DetachedCriteria.ALIAS_TO_ENTITY_MAP); Criteria executableCriteria = queryCirteriaOuter.getExecutableCriteria(session); Map map = (Map) executableCriteria.list().get(0); System.out.println("result: "+map.get("rowCount")); t.commit();
没问题, 结果很好地显示了出来.
这里生成的SQL为select count(*) as y0_ from S_LOV this_ where this_.list_Type in (select this_.COLUMN_NAME as y0_ from S_LOV_LINK this_ where this_.TABLE_NAME like ?),别名上没问题, 都是y0_ , 这样就排除了hibernate在对ResultSet组装时别名相同出错的可能性了.(再说,Hibernate真正组装的是外围查询的结果,而子查询只在数据库里执行跟hibernate在包装ResultSet时没关系)
尝试点3: 直接用JDBC的connection来执行尝试1中生成SQL. 由于尝试1跟2不同的地方是,尝试1中用的是视图对应的Java类(类ContractTrade对应的 UPLOAD_CONTRACT_ITRADE_VIEW是数据库里的一个视图),而尝试2中两个java类对应着数据库里真正的表. 想到可能是hibernate对那个视图执行SQL时出了什么问题.于是又用下面的代码来实直接执行SQL会不会出什么问题.
SessionFactory sessionFactory = HiberUtil.getSessionFactoryOracle(); Session session = sessionFactory.getCurrentSession(); Transaction t = session.beginTransaction(); Connection conn = session.connection(); String sql = "select count(*) as y0_ from UPLOAD_CONTRACT_ITRADE_VIEW this_ "+ "where this_.DEPT_ID=24 and this_.CONTRACT_ID "+ "not in (select this0__.LINK_CONT_ID as y0_ from CONTRACT_OTHER_LINK this0__)"; PreparedStatement st = conn.prepareStatement(sql); ResultSet rs = st.executeQuery(sql); rs.next(); int result = rs.getInt("y0_"); System.out.println("result: "+ result); t.commit();
还是没问题.
尝试点4: 从Hibernate源码上看最终是卡在了哪. 于是在IDE里多次设置断点, 最终发现在类org.hibernate.jdbc.AbstractBatcher方法getResultSet(PreparedStatement ps)第一行的ResultSet rs = ps.executeQuery();一句卡了.
这是为什么?追代码时发现这个ps就是hibernate转换传来的DetachedCriteria生成SQL后对应的 PreparedStatement, 跟上面尝试3中PreparedStatement st = conn.prepareStatement(sql);类似. 那为什么我的能执行,这里的hibernate自动生成的就失败了尼?
------------------------------------
问题记录完了, 没有解决.
写在这里,一是希望大家能给些指点,二是想着以后对hibernate认识加深后想解决这个问题时不必再从头研究.