Hibernate和静态运行HQL查询

时间:2009-12-10 17:23:11

标签: sql hibernate hql

我想“干运行”Hibernate HQL查询。那就是我想知道Hibernate从给定的HQL查询中执行什么实际的SQL查询,而不实际对真实数据库执行HQL查询。

我可以访问表的hibernate映射,HQL查询字符串,我的数据库的dialect。如果需要,我也可以访问数据库。

现在,我怎样才能找到Hibernate可以从我的HQL生成的所有SQL查询,而无需对任何数据库实际执行查询?有没有这方面的工具?

请注意,可以从一个HQL查询生成许多SQL查询,并且生成的SQL查询集可能会因数据库的内容而异。

我不是在询问HQL查询执行时如何记录SQL查询。

编辑:我不介意连接数据库来获取一些元数据,我只是不想执行查询。

编辑:我也知道对查询应用了哪些限制和偏移。我还有将要绑定到查询的实际参数。

2 个答案:

答案 0 :(得分:5)

简短的回答是“你不能”。答案如下。

您可以采取两种方法:

A)查看HQLQueryPlan class,特别是getSqlStrings() method。它不会得到完全 SQL,因为在实际执行查询之前会涉及进一步的预处理(参数绑定,应用限制/偏移等等)但它可能足够接近你的想。

这里要记住的是,您需要一个实际的SessionFactory实例来构建HQLQueryPlan,这意味着如果没有“连接到任何”,您将无法执行此操作数据库”。但是,您可以使用内存数据库(SqlLite等)并让Hibernate自动为其创建必要的模式。

B)从ASTQueryTranslatorFactory开始,然后进入AST / ANTLR疯狂。从理论上讲,您可以将一个可以在不依赖元数据的情况下工作的解析器组合在一起,但是我最难想象您正在努力为此做些什么是值得的。也许你可以澄清一下? 是更好的方法。

答案 1 :(得分:2)

更新:对于某些HQL的离线,干运行,直接使用HQLQueryPlan是一种很好的方法。如果你想截取应用程序中的每个查询,当它正在运行并记录SQL时,你将不得不使用代理和反射,如下所述。

查看this answer的Criteria Queries。

对于HQL,它是相同的概念 - 您必须转换为Hibernate实现类和/或访问私有成员,因此它不是受支持的方法,但它将适用于3.2-3.3版本的Hibernate。以下是从HQL访问查询的代码(查询是session.createQuery(hql_string)返回的对象:

Field f = AbstractQueryImpl.class.getDeclaredField("session");
f.setAccessible(true);
SessionImpl sessionImpl = (SessionImpl) f.get(query);
Method m = AbstractSessionImpl.class.getDeclaredMethod("getHQLQueryPlan", new Class[] { String.class, boolean.class });
m.setAccessible(true);
HQLQueryPlan plan = (HQLQueryPlan) m.invoke(sessionImpl, new Object[] { query.getQueryString(), Boolean.FALSE });
for (int i = 0; i < plan.getSqlStrings().length; ++i) {
  sql += plan.getSqlStrings()[i];
}

我会将所有这些包装在try / catch中,以便在日志记录不起作用的情况下继续查询。

可以代理你的会话然后代理你的查询,这样你就可以在运行之前记录sql和每个查询的参数(hql,sql,criteria),而不需要构建查询的代码必须做任何事情(只要从您控制的代码中检索初始会话。