我可以从JPA查询对象中获取SQL字符串吗?

Li *_*Yin 17 sql jpa

我可以知道如何从JPA查询中获取sql吗?或者说,将JPA查询转换为SQL字符串?非常感谢你!

Kar*_*l S 11

对于Eclipselink:您可以通过以下方式提取SQL:

query.unwrap(EJBQueryImpl.class).getDatabaseQuery().getSQLString()
Run Code Online (Sandbox Code Playgroud)

它只在查询执行后才有效.

  • 为我工作,但我的项目没有EJBQueryImpl.class(我使用String rtn = query.unwrap(org.hibernate.Query.class).getQueryString();) (2认同)

Mat*_*ndy 7

如果您只想知道如何将JPQL或Criteria Query转换为数据库的SQL方言,则可以在持久性xml中启用细粒度日志记录,然后查看日志文件.

属性名称和值取决于您的JPA实现.以下是EclipseLink 的persistence.xml相关部分的示例:

<properties>
    <property name="eclipselink.logging.level" value="FINEST"/>
</properties>
Run Code Online (Sandbox Code Playgroud)


Vla*_*cea 7

JPA规范

虽然没有标准的 JPA 功能来实现这个目标,但您仍然可以Query使用 JPA 提供程序特定的 API从 JPQL 或 Criteria API 中提取 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 查询中获取 SQL 语句

假设我们有以下 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
);
Run Code Online (Sandbox Code Playgroud)

使用 Hibernate Types,提取 Hibernate 生成的 SQL 查询就这么简单:

String sql = SQLExtractor.from(jpql);
Run Code Online (Sandbox Code Playgroud)

而且,如果我们记录提取的 SQL 查询:

LOGGER.info("""
    The JPQL query: [
        {}
    ]
    generates the following SQL query: [ 
        {}
    ]
    """,
    jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
    sql
);
Run Code Online (Sandbox Code Playgroud)

我们得到以下输出:

- 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)
]
Run Code Online (Sandbox Code Playgroud)

请注意,我们将 JPA 解包Query到 Hibernateorg.hibernate.query.Query接口,该接口提供了getQueryString我们可以用来记录关联的 JPQL 查询字符串的方法。

从 JPA Criteria API 查询中获取 SQL 语句

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
);
Run Code Online (Sandbox Code Playgroud)

运行上述测试用例时,我们得到以下 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
]
Run Code Online (Sandbox Code Playgroud)

Criteria API 首先编译为 JPQL 查询,如getQueryString()方法调用所示。

中间 JPQL 查询进一步转换为 SQL 查询,该查询由SQLExtractor实用程序正确解析。