Can I get the SQL string from a JPA Query object?

前端 未结 8 624
慢半拍i
慢半拍i 2021-01-01 12:36

May I know how can I get the sql from a JPA query? or let\'s say, convert the JPA query to a SQL string? Thank you very much!

8条回答
  •  抹茶落季
    2021-01-01 13:16

    Since this is a very common question, this answer is based on this article I wrote on my blog.

    JPA Specification

    While there is not standard JPA functionality to achieve this goal, you can still extract the SQL query from a JPQL or Criteria API Query using the JPA provider-specific API.

    Hibernate Types

    Starting with the 2.9.11 version, the Hibernate Types open-source project offers the SQLExtractor utility that allows you to get the SQL query from any JPQL or Criteria API query, no matter you are using Hibernate 5.4, 5.3, 5.2, 5.1, 5.0, 4.3, 4.2, or 4.1.

    Get the SQL statement from a JPQL Query

    Let's assume we have the following JPQL query:

    Query jpql = entityManager.createQuery("""
        select 
           YEAR(p.createdOn) as year, 
           count(p) as postCount 
        from 
           Post p 
        group by 
           YEAR(p.createdOn)
        """, Tuple.class
    );
    

    With Hibernate Types, extracting the Hibernate-generated SQL query is as simple as that:

    String sql = SQLExtractor.from(jpql);
    

    And, if we log the extracted SQL query:

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

    We get the following output:

    - 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)
    ]
    

    Notice that we unwrapped the JPA Query to the Hibernate org.hibernate.query.Query interface which provided the getQueryString method we can use to log the associated JPQL query string.

    Get the SQL statement from a JPA Criteria API Query

    The SQLExtractor is not limited to JPQL queries. You can use it with Criteria API queries as well, as illustrated by the following example:

    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    
    CriteriaQuery criteria = builder.createQuery(PostComment.class);
    
    Root postComment = criteria.from(PostComment.class);
    Join 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
    );
    

    When running the above test case, we get the following SQL query:

    - 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
    ]
    

    The Criteria API is first compiled to a JPQL query, as illustrated by the getQueryString() method call.

    The intermediary JPQL query is further translated to an SQL query, which is properly resolved by the SQLExtractor utility.

    For more details about this feature, check out this article.

提交回复
热议问题