Hibernate(十六): DetachedCriteria子查询与ALIAS_TO_ENTITY

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

你可能感兴趣的:(sql,Hibernate,jdbc,ide)