我可以知道如何从JPA查询中获取sql吗?或者说,将JPA查询转换为SQL字符串?非常感谢你!
答案 0 :(得分:11)
对于Eclipselink:您可以通过以下方式提取SQL:
var contact = m_someFactory.Create<IContact>(contact, Page.ID);
var organization = contact.Organization;
仅在执行 后才能使用。
答案 1 :(得分:7)
如果您只想知道如何将JPQL或Criteria Query转换为数据库的SQL方言,则可以在 persistence xml 中启用细粒度日志记录,然后查看日志文件。
属性名称和值取决于您的JPA实现。以下是EclipseLink的 persistence.xml 相关部分的示例:
<properties>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
答案 2 :(得分:4)
由于这是一个非常常见的问题,所以此答案基于我在博客上写的this article。
虽然没有标准的JPA功能可以实现此目标,但是您仍然可以使用JPA提供程序特定的API从JPQL或Criteria API Query
中提取SQL查询。
从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查询:
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)
]
请注意,我们已将JPA
Query
解包到Hibernateorg.hibernate.query.Query
接口,该接口提供了getQueryString
方法,可用于记录关联的JPQL查询字符串。
SQLExtractor
不仅限于JPQL查询。您也可以将其与Criteria API查询一起使用,如以下示例所示:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PostComment> criteria = builder.createQuery(PostComment.class);
Root<PostComment> postComment = criteria.from(PostComment.class);
Join<PostComment, Post> post = postComment.join("post");
criteria.where(
builder.like(post.get("title"), "%Java%")
);
criteria.orderBy(
builder.asc(postComment.get("id"))
);
Query criteriaQuery = entityManager.createQuery(criteria);
String sql = SQLExtractor.from(criteriaQuery);
assertNotNull(sql);
LOGGER.info("""
The Criteria API, compiled to this JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
在运行上述测试用例时,我们得到以下SQL查询:
- The Criteria API, compiled to this JPQL query: [
select
pc
from
PostComment as pc
inner join
pc.post as p
where
p.title like :param0
order by
pc.id asc
]
generates the following SQL query: [
SELECT
pc.id AS id1_1_,
pc.post_id AS post_id3_1_,
pc.review AS review2_1_
FROM
post_comment pc
INNER JOIN
post p ON pc.post_id=p.id
WHERE
p.title LIKE ?
ORDER BY
pc.id ASC
]
首先将Criteria API编译为JPQL查询,如getQueryString()
方法调用所示。
中间JPQL查询被进一步转换为SQL查询,该查询可通过SQLExtractor
实用程序正确地解决。
有关此功能的更多详细信息,请查看this article。
答案 3 :(得分:3)
除了启用像@Matt Handy这样的日志记录之外,还可以在运行时使用eclipselink获取特定查询的SQL字符串,如here所述。
答案 4 :(得分:2)
如果有一种方法可以从javax.persistence.Query中提取'提取'JPQL字符串(使用params的占位符,或者在params填充后使用最终的JPQL),那么你可能感兴趣了(其中一个可能的子类更多)精确), - 在这种情况下根据JPA规范合同是不可能的。但是,这可能是JPA实现的假设(例如,NamedQueryImpl可能有#toJPQLString(),您可以通过强制转换访问),但我对此表示怀疑。 即使有可能,我也不认为执行此类操作是一个很好的代码。我建议找另一个设计解决方案(为此你可以指定你有什么样的实际问题)。例如,如果您正在动态构建查询,可以使用JPA Criteria API,并且与“构建”JPA查询一起,您可以维护反映查询逻辑的内部数据结构。
答案 5 :(得分:1)
使用Hibernate作为提供程序,您可以启用以下属性:
hibernate.show_sql
将所有SQL语句写入控制台。这是将日志类别org.hibernate.SQL设置为debug的替代方法。 (例如,true | false)
hibernate.format_sql
在日志和控制台中打印SQL。 (例如,true | false)
或者,如上所述,您可以启用日志记录器的调试级别
org.hibernate.SQL
记录执行时的所有SQL DML语句
答案 6 :(得分:0)