如何获取 JPA 生成的 SQL 查询?

Posted

技术标签:

【中文标题】如何获取 JPA 生成的 SQL 查询?【英文标题】:How to get the JPA generated SQL query? 【发布时间】:2012-12-30 19:16:11 【问题描述】:

我使用 JPA 规范和 Hibernate 作为我的供应商。我需要以某种方式获取发送到数据库的生成的 SQL 查询(打印到 sysout)并将其保存为一个简单的字符串。

有没有办法做到这一点?

编辑

让我更清楚一点:我不需要休眠日志。我需要能够在不同的数据库上执行相同的查询。因此,我需要按原样获取 SQL 查询,并将其保存在一个普通的 String 变量中。

编辑 2

是否有一个实用程序可以提供一个 bean,它会自动生成一个插入查询?我可以在这里以某种方式使用 Hibernate bean 吗?我知道这是一个节拍复合体。

谢谢,

伊多布

【问题讨论】:

编辑你的问题,不太清楚你问的是spring data jpa模块,spring可以在没有spring data的情况下使用jpa 你找到解决办法了吗? 看起来没有一个干净的解决方案。您也许可以通过参数将 EntityManager 传递给规范实现,然后使用此处找到的代码 antoniogoncalves.org/2012/05/24/… @ido-barash 您是否获得了“我需要按原样获取 SQL 查询,并将其保存在普通字符串变量中”的解决方案。 ?如果是,请告诉我。 没有。我放弃了 【参考方案1】:

像这样创建一个 bean。

@Bean
public JpaVendorAdapter jpaVendorAdapter()
    HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
    jpaVendorAdapter.setGenerateDdl(true);
    jpaVendorAdapter.setShowSql(true);

    return jpaVendorAdapter;

如果您使用 Spring Boot,请将其添加到您的 @Configuration 中。

由此创建的日志可在 mysql 工作台中执行。 您说您正在使用 JPA 和 Hibernate。除非您支持的数据库受 JPA 支持,否则别无他法。在这种情况下,您可以实现一个 AbstractJpaVendorAdapter。

【讨论】:

酷。能够在我的控制台中看到 sql 语句 :) 如果我还想查看参数值?【参考方案2】:

您的问题的简单答案是否定的。您想要做的是许多开发人员也想做的事情,但它不是 JPA 规范的一部分,因此获取生成的 SQL 的能力将取决于供应商决定这样做。使用 Hibernate 获取 SQL 的唯一方法是通过日志。

【讨论】:

通过 Hibernate 的示例找到了这个。 ***.com/questions/554481/… 。使用 Hibernate 可以在 String 中获取 SQL【参考方案3】:

您必须启用 log4j 日志记录并为 Hibernate 添加一个附加程序以显示查询。

这里已经描述过了:How to print a query string with parameter values when using Hibernate

【讨论】:

这不是我问的! 我需要将查询作为字符串获取以备后用。不在日志中查看。【参考方案4】:

如果我对您的理解正确,您希望获取 Hibernate 在一个数据库上执行的插入查询,并通过代码通过entityManager#executeUpdate 或类似方法在另一个数据库上运行它。

Hibernate 不会公开生成的查询,因为它特定于目标数据库的方言。因此,即使要获得插入查询,也可能毫无意义。

但是,在您的情况下,您可以创建两个数据库连接(通过两个DataSourceEntityManagerFactory 在您的情况下)并为两个数据库调用两次dao.persist(entity),然后让 Hibernate 处理查询构造部分。

编辑:这里的查询是指本地查询,两个数据库的 HQL 查询是相同的。 希望对您有所帮助。

【讨论】:

【参考方案5】:

尝试在 LocalContainerEntityManagerFactoryBean 的实例中添加属性,它对我有用:-

@EnableJpaRepositories(basePackages = "org.common.persistence.dao")
public class PersistenceJPAConfig 

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() 
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[]  "org.common.persistence.model" );
        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());
        return em;
    

    final Properties additionalProperties() 
        final Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("showSql", "true");
        hibernateProperties.setProperty("hibernate.show_sql", "true");
        hibernateProperties.setProperty("hibernate.format_sql", "true");
        hibernateProperties.setProperty("hibernate.query.substitutions", "false");
        return hibernateProperties;
    

【讨论】:

【参考方案6】:

我不知道生成的查询是什么意思,但是如果您使用 Hibernate 并且拥有 javax.persistence.Query query,您可以很容易地获得 HQL 字符串(对于 EclipseLink,它是类似的)。如果你有 HQL,你可以用 QueryTranslator 将它翻译成 SQL。

// Get HQL
String hqlQueryString = query.unwrap(org.hibernate.query.Query.class).getQueryString();

// Translate HQL to SQL
ASTQueryTranslatorFactory queryTranslatorFactory = new ASTQueryTranslatorFactory();
SessionImplementor hibernateSession = em.unwrap(SessionImplementor.class);
QueryTranslator queryTranslator = queryTranslatorFactory.createQueryTranslator("", hqlQueryString, Collections.emptyMap(), hibernateSession.getFactory(), null);
queryTranslator.compile(Collections.emptyMap(), false);
String sqlQueryString = queryTranslator.getSQLString();

【讨论】:

以上是关于如何获取 JPA 生成的 SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Spring Boot JPA 执行具有 INTERVAL 子句的本机 SQL 查询?

如何通过 JPA 查询按子类实体值获取父实体?

JPA 一个实体中的两个惰性集合 - 如何运行 JPA 查询以获取实体和只有一个集合

jpa如何懒加载大字段,懒加载之后又如何获取懒加载字段

如何在JAVA JPA Spring Boot中的一个SQL查询中选择多个数据

通过 JPA 标准查询从 SQL 视图获取列表时出错