跟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认识加深后想解决这个问题时不必再从头研究.