如何以编程方式将 HQL 转换为 SQL 查询(不记录)
Posted
技术标签:
【中文标题】如何以编程方式将 HQL 转换为 SQL 查询(不记录)【英文标题】:How to convert HQL to SQL Query programmatically (without logging) 【发布时间】:2013-08-25 09:22:12 【问题描述】:我正在执行以下 HQL,它正在正确执行
String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();
现在,我还想将后端生成的 sql 记录在日志中以供支持用户使用。
我想使用QueryTranslator,请指教如何为相应的HQL生成sql,请指教如何实现。
【问题讨论】:
【参考方案1】:你可以使用hibernate QueryTranslator:
String hqlQueryString = hqlQuery.getQueryString();
ASTQueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
SessionImplementor hibernateSession = entityManager.unwrap(SessionImplementor.class);
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator("", hqlQueryString, java.util.Collections.EMPTY_MAP, hibernateSession.getFactory());
queryTranslator.compile(java.util.Collections.EMPTY_MAP, false);
String sqlQueryString = queryTranslator.getSQLString();
【讨论】:
不幸的是,这不适用于 Hibernate 5 :( 有新的第 5 个参数EntityGraphQueryHint
。
您可以将 null 作为第 5 个参数传递。它应该可以工作。
这只会返回 hql 而不是 sql;问题是:“现在我还想将后端生成的 sql 记录在支持用户的日志中”
代码最终返回“sqlQueryString”变量中hqlQuery的SQL等价。
很遗憾没有使用列的别名。【参考方案2】:
我相信您想要前 2 个答案的组合
String hqlQueryString = query.unwrap(org.hibernate.Query.class).getQueryString();
ASTQueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
SessionImplementor hibernateSession = em.unwrap(SessionImplementor.class);
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator("", hqlQueryString, java.util.Collections.EMPTY_MAP, hibernateSession.getFactory());
queryTranslator.compile(java.util.Collections.EMPTY_MAP, false);
String sqlQueryString = queryTranslator.getSQLString();
【讨论】:
createQueryTranslator 还需要一个参数:EntityGraphQueryHint。 翻译后,“:variable”等参数全部被“?”替换,无法设置参数值。我也尝试设置参数,然后将其转换为 SQL,但效果不佳。注意:我这样做是为了将其附加为计数的子查询,因为 group by 内有许多参数,而 HQL 不支持这个【参考方案3】:在 Hibernate 的更高版本中使用 TypedQuery 也可以使用以下代码
String hqlQueryString=typedQuery.unwrap(org.hibernate.query.Query.class).getQueryString();
ASTQueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
SessionImplementor hibernateSession = entityManager.unwrap(SessionImplementor.class);
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator("", hqlQueryString, java.util.Collections.EMPTY_MAP, hibernateSession.getFactory(), null);
queryTranslator.compile(java.util.Collections.EMPTY_MAP, false);
String sqlQueryString = queryTranslator.getSQLString();
【讨论】:
【参考方案4】:我在网上找到了下一个解决方案:
QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory();
SessionFactoryImplementor factory = (SessionFactoryImplementor) getSessionFactory();
QueryTranslator translator = translatorFactory.
createQueryTranslator(hqlQueryText, hqlQueryText, Collections.EMPTY_MAP, factory);
translator.compile(Collections.EMPTY_MAP, false);
translator.getSQLString();
来源:http://narcanti.keyboardsamurais.de/hibernate-hql-to-sql-translation.html
【讨论】:
【参考方案5】:这行得通,其他答案对于现代版本的休眠有问题:
String hqlQueryString = query.unwrap(org.hibernate.Query.class).getQueryString();
ASTQueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
SessionImplementor hibernateSession = entityManager.unwrap(SessionImplementor.class);
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator("", hqlQueryString, java.util.Collections.EMPTY_MAP, hibernateSession.getFactory(), null);
queryTranslator.compile(java.util.Collections.EMPTY_MAP, false);
String sqlQueryString = queryTranslator.getSQLString();
【讨论】:
今天这对我有用...似乎有这个问题的几个版本飞来飞去...【参考方案6】:休眠类型
从 2.9.11 版本开始,Hibernate Types 开源项目提供了SQLExtractor
实用程序,允许您从任何 JPQL 或 Criteria API 查询中获取 SQL 查询,无论您使用的是 Hibernate 5.4、5.3 、5.2、5.1、5.0、4.3、4.2 或 4.1。
从 JPQL (HQL) 查询中获取 SQL 语句
假设我们有以下 JPQL (HQL) 查询:
Query jpql = entityManager.createQuery("""
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
""", Tuple.class
);
使用 Hibernate 类型,提取 Hibernate 生成的 SQL 查询就这么简单:
String sql = SQLExtractor.from(jpql);
而且,如果我们记录提取的 SQL 查询:
LOGGER.info("""
The JPQL query: [
]
generates the following SQL query: [
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
我们得到以下输出:
- The JPQL query: [
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
]
generates the following SQL query: [
SELECT
extract(YEAR FROM sqlextract0_.created_on) AS col_0_0_,
count(sqlextract0_.id) AS col_1_0_
FROM
post p
GROUP BY
extract(YEAR FROM p.created_on)
]
请注意,我们将 JPQL (HQL)
Query
解包到 Hibernateorg.hibernate.query.Query
接口,该接口提供了getQueryString
方法,我们可以使用该方法记录关联的 JPQL 查询字符串。
【讨论】:
【参考方案7】:您可以使用 unwrap 方法获取查询。
String queryString = query.unwrap(org.hibernate.Query.class).getQueryString();
【讨论】:
哪个版本的hibernate有一个带有unwrap方法的查询? java6持久化api的一部分docs.oracle.com/javaee/6/api/javax/persistence/Query.html 这仅适用于获取 HQL 查询而不是 SQL 查询以上是关于如何以编程方式将 HQL 转换为 SQL 查询(不记录)的主要内容,如果未能解决你的问题,请参考以下文章