`
buptchenliang
  • 浏览: 4872 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Hibernate在from子句中使用子查询

阅读更多
    最近用到了Hibernate来作为数据处理部分的框架,离线criteria的确很好用,但在分页上确实让人头疼。要想分页就需要记录的总条数,如果只是一般的查询只需要
criteria.setProjection(Projections.rowCount());

就可以了,但如果是distinct的查询,记录条数和你所需查询的列有关,那么可以这样
Projections.countDistinct(propertyName);

问题来了,好像只能有一列啊。没错在标准sql中的distinct count也只能是一列的,但当有多列查询的时候怎么办呢?criteria有个接口可以设定结果值为distinct,就这样
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

但是这样做的问题在于,他是先执行,后在程序中distinct,这样会导致每页的记录可能不同,而且性能低下。
换个思路在写sql的时候可以这样写
select count(*) from (select distinct xxxxxx)

也就是说在外层套一个count 而真实的查询语句在from子句中,成为一个子查询。那看看如何变成Hibernate的形式吧。我在网站上搜索了好久,终于得出一个结论(经过Hibernate文档证明了)Hibernate不支持from子句中存在子查询,他们认为from应该是一个映射了的对象,子查询和他们的思想不符。
好吧,那再换个思路,Hibernate本身只是一个映射的过程,那么实际执行还是需要JDBC实现。如果是JDBC就需要sql语句,我们把criteria中蕴含的sql语句提取出来,然后加上我们外层的计数部分,然后再像Hibernate一样绑定参数就可以了,因为外层没有参数占位符,所以也不会影响Hibernate按位置绑定参数,因为没有接口,那只能读源码了。果然,hibernate最后通过sql(就是log中看到的那个)生成一个PreparedStatement,并通过方法绑定参数。废话少说,直接来个破冰之旅。
	/**
	 * 因为需要修改sql,就要传入你新的sql,criteria必须是绑定session的
	 * 因为我们用到了session
	 * @param sql
	 * @param criteria
	 * @return
	 */
	public static List<List> wrapAndExecute(String sql, Criteria criteria) {
		ResultSet rs = null;//最后的结果集
		PreparedStatement ps = null;//我们自己的PreparedStatement
		Connection connection = null;//session中获取的连接
		try {
			//先转型
			CriteriaImpl criteriaImpl = (CriteriaImpl) criteria;
//			获取SessionImplementor类型的session
			SessionImplementor session = criteriaImpl.getSession();
//			获取factory
			SessionFactoryImplementor factory = session.getFactory();
//			获取CriteriaQueryTranslator对象,按照Hibernate源码中的方式生成
			CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteriaImpl, criteriaImpl
					.getEntityOrClassName(), CriteriaQueryTranslator.ROOT_SQL_ALIAS);
//			从CriteriaQueryTranslator对象中获取保存参数的QueryParameters对象
			QueryParameters queryParameters = translator.getQueryParameters();
//			从factory中获取implementors,一般只用一个
			String[] implementors = factory.getImplementors(criteriaImpl.getEntityOrClassName());
//			因为只用一个,所以只需要一个loader,按照Hibernate源码中的方式新建
//			注意有些地方由于非public所以需要用反射,反射部分代码就不贴了,注意invokeMethod要从子类找到父类,直到object
//			因为有些方法是写在父类中的
			Loader loader = new CriteriaLoader((OuterJoinLoadable) ReflectUtil.invokeMethod(session,
					"getOuterJoinLoadable", new Class[] { String.class }, new Object[] { implementors[0] }), factory,
					criteriaImpl, implementors[0], ((SessionImpl) session).getLoadQueryInfluencers());
//			按照Hibernate源码方法获取walker
			CriteriaJoinWalker walker = new CriteriaJoinWalker((OuterJoinLoadable) factory
					.getEntityPersister(implementors[0]), translator, factory, criteriaImpl, criteriaImpl
					.getEntityOrClassName(), session.getLoadQueryInfluencers());
//			获取了criteria的sql
			String criteriaSql = walker.getSQLString();			
//			用传入的sql代替,注意PLACEHOLDER代表criteriaSql的占位符
			sql = sql.replace(PLACEHOLDER, criteriaSql);
//			获取session中的连接
			connection = session.getJDBCContext().getConnectionManager().getConnection();
//			构建新的PreparedStatement
			ps = connection.prepareStatement(sql);
//			注意一定要过滤过参数才能绑定
			queryParameters.processFilters(criteriaSql, session);
//			通过反射绑定参数
			ReflectUtil.invokeMethod(loader, "bindParameterValues", new Class[] { PreparedStatement.class,
					QueryParameters.class, int.class, SessionImplementor.class }, new Object[] { ps, queryParameters,
					1, session });
//			获取结果集
			rs = session.getBatcher().getResultSet(ps);
......

呼,好了,终于抠出了criteria的东西了。
最后值得注意的是,由于ResultSet和PreparedStatement是自己创建的,所以需要自己维护,就是要注意关闭咯。至于connection由于是session中获取的,可以不用管,否则这个session如果还有其他操作connection关了就要抛错了。
0
0
分享到:
评论
2 楼 buptchenliang 2012-09-05  
liuluoqiu 写道
lz,这样是可以获得原生sql,但是里面的参数是?,如何才能显示?中内容啊

本文目的不是获取完全的sql,只是通过这种方式个性化sql。当然你想获取到完整的sql也是可以的,所有的参数都在QueryParameters 这个类里,你完全可以从这个对象中将每个参数获取,结合带有?的sql就可以得到完整的sql了。
1 楼 liuluoqiu 2012-06-15  
lz,这样是可以获得原生sql,但是里面的参数是?,如何才能显示?中内容啊

相关推荐

    hibernate子查询

    这意味着你需要为这个临时的子查询结果创建一个新的Java类,然后在Hibernate映射文件中定义这个类,使用`subselect`属性指定子查询的SQL语句。这样,Hibernate就会根据这个子查询来获取和管理数据,而不是直接操作...

    hibernate 中HQL语句查询学习笔记

    在多表查询中,表之间的关联关系非常重要。 ##### 表中的数据 为了演示多表查询,我们继续使用前面提到的`student`、`course`和`sc`表。 ##### 修改持久化类 为了实现关联关系,需要在持久化类中进行相应的修改...

    Hibernate-HQL-查询-Query资料

    - HQL支持在SELECT、FROM、WHERE子句中使用子查询。 - 子查询可以返回单个值,也可以返回对象列表。 8. **参数化查询** - 使用问号(?)作为占位符,防止SQL注入攻击。 - 可以使用Query接口的setParameter()...

    hibernate实现递归查询

    本文将深入探讨如何使用Hibernate实现递归查询,以解决在数据层次结构中涉及父节点与子节点关系时的问题。递归查询通常用于处理树形结构的数据,例如组织结构、菜单系统或者文件目录等。 首先,我们需要了解递归的...

    最全Hibernate 参考文档

    14.2. from子句 14.3. 关联(Association)与连接(Join) 14.4. select子句 14.5. 聚集函数 14.6. 多态查询 14.7. where子句 14.8. 表达式 14.9. order by子句 14.10. group by子句 14.11. 子查询 14.12. HQL示例 14.13...

    Hibernate+中文文档

    14.2. from子句 14.3. 关联(Association)与连接(Join) 14.4. join 语法的形式 14.5. select子句 14.6. 聚集函数 14.7. 多态查询 14.8. where子句 14.9. 表达式 14.10. order by子句 14.11. group by子句 ...

    hibernate查询语言hql

    HQL允许在`WHERE`子句中使用子查询,例如: ```java query = session.createQuery("from User u where u in (select u2 from User u2 where u2.age &gt; 30)"); ``` 这里查询所有年龄大于30岁的用户。 ### 组合查询 ...

    hibernate面试题.doc

    - 在查询中使用JOIN操作,例如`from Customer as customer join fetch customer.buySet`实现Eager Loading,一次性加载关联数据;`from Customer as customer join customer.buySet`则表示Lazy Loading,仅在访问...

    HQL(Hibernate Query Language):

    7. **子查询**:在SELECT或WHERE子句中使用子查询,提供更灵活的查询方式。 8. **动态实例化**:允许在查询中创建新的对象实例,例如"FROM User AS u WHERE u.email LIKE '%%' ORDER BY u.username DESC"。 HQL还...

    hibernate3.2 (十)HQL查询

    2. 子查询:可以在HQL中嵌套查询,例如`select u from User u where u.id in (select a.userId from Address a where a.city='上海')`,找出所有有上海地址的用户。 3. 排序:使用`order by`子句可以对查询结果进行...

    Hibernate Query Language

    - **其他构造**:包括聚合函数、表达式、排序子句、分组子句、多态选择以及子查询。 ### 4. HQL与SQL的区别 - **面向对象**:HQL完全面向对象,能够处理继承、多态和关联等概念。 - **大小写敏感性**:HQL对查询...

    Hibernate中文详细学习文档

    14.2. from子句 14.3. 关联(Association)与连接(Join) 14.4. join 语法的形式 14.5. select子句 14.6. 聚集函数 14.7. 多态查询 14.8. where子句 14.9. 表达式 14.10. order by子句 14.11. group by子句 ...

    hibernate映射配置文件不支持union联合查询[参照].pdf

    在软件开发领域,尤其是...总的来说,当遇到类似问题时,开发者需要仔细检查SQL语句的语法和结构,同时评估是否可以通过调整查询策略、优化数据模型或利用其他工具来避免直接在Hibernate映射文件中使用复杂的子查询。

    Hibernate-HQL.rar_HQL_hibernate hql

    2. 避免在HQL中使用SQL函数:尽量用Hibernate提供的函数,以确保跨数据库兼容性。 3. 优化查询性能:合理设计数据库索引,避免全表扫描,尽量减少JOIN操作。 总之,Hibernate-HQL是Java开发中处理数据库查询的重要...

    06_传智播客hibernate教程_完善HibernateUtil类及hql查询入门

    除了基本的查询,HQL 还支持更复杂的操作,如联接查询、子查询、聚合函数等。例如,如果你需要根据用户名查找用户,可以这样写: ```java String hql = "from User where username = :username"; query = session....

    hibernate3.2中文文档(chm格式)

    14.2. from子句 14.3. 关联(Association)与连接(Join) 14.4. join 语法的形式 14.5. select子句 14.6. 聚集函数 14.7. 多态查询 14.8. where子句 14.9. 表达式 14.10. order by子句 14.11. group by子句 ...

    Hibernate查询语句教程a

    - **子查询**:可以在HQL中嵌套查询,如`from Cat as cat where cat.id in (select dog.id from Dog as dog)`。 HQL的灵活性和面向对象的特性使得它成为在Hibernate中进行复杂查询的理想选择。通过理解和熟练使用...

    Hibernate Query Language基础使用详解

    例如,可以使用子查询来找出所有平均成绩超过90分的课程:`FROM Course c WHERE AVG(SELECT sc.grade FROM SC sc WHERE sc.cno = c.cno) &gt; 90`。 QBC(Query By Criteria)是另一种查询方式,它提供了一种基于Java ...

Global site tag (gtag.js) - Google Analytics