You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java代码中获取Hibernate生成的SQL而非仅在控制台打印?

在Java代码中获取Hibernate生成的SQL语句

当然可以!你完全不用只依赖控制台输出,有几种实用的方法能直接在代码里捕获Hibernate生成的SQL,我给你详细拆解下:

方法1:自定义Hibernate Interceptor实时拦截SQL

这是最直接的实时获取方式,通过拦截器能在SQL生成的第一时间拿到它,适合需要即时处理的场景。

先定义一个自定义拦截器,继承EmptyInterceptor并重写onPrepareStatement方法:

import org.hibernate.EmptyInterceptor;

public class SQLCaptureInterceptor extends EmptyInterceptor {
    private String capturedSQL;

    @Override
    public String onPrepareStatement(String sql) {
        // 这里直接拿到Hibernate生成的完整SQL
        this.capturedSQL = sql;
        // 必须返回原SQL,否则会中断查询执行
        return super.onPrepareStatement(sql);
    }

    public String getCapturedSQL() {
        return capturedSQL;
    }
}

然后在使用Session时注册这个拦截器:

// 创建拦截器实例
SQLCaptureInterceptor interceptor = new SQLCaptureInterceptor();
// 绑定拦截器到Session
Session session = sessionFactory.withOptions().interceptor(interceptor).openSession();

// 执行你的查询操作
session.createQuery("FROM User WHERE id = :userId", User.class)
       .setParameter("userId", 1001)
       .getSingleResult();

// 直接获取捕获到的SQL
String generatedSQL = interceptor.getCapturedSQL();
System.out.println("Hibernate生成的SQL:" + generatedSQL);

如果用JPA的EntityManager,可以转成Hibernate Session后设置:

EntityManager em = entityManagerFactory.createEntityManager();
SQLCaptureInterceptor interceptor = new SQLCaptureInterceptor();
// 把EntityManager转成Hibernate Session
Session session = em.unwrap(Session.class);
session.getSessionFactory().getSessionOptions().setInterceptor(interceptor);

// 执行查询后获取SQL
String sql = interceptor.getCapturedSQL();

方法2:利用Hibernate Statistics API事后获取SQL

这个方法适合需要回溯已执行SQL的场景,需要先开启统计功能。

首先在Hibernate配置中开启统计:

# 在hibernate.cfg.xml或application.properties中添加
hibernate.generate_statistics=true

然后在代码中获取统计数据:

// 获取SessionFactory的统计实例
Statistics stats = sessionFactory.getStatistics();
stats.setStatisticsEnabled(true);

// 执行你的查询操作
session.createQuery("FROM User WHERE status = :status", User.class)
       .setParameter("status", "ACTIVE")
       .list();

// 获取所有执行过的SQL查询
String[] executedQueries = stats.getQueries();
for (String sql : executedQueries) {
    System.out.println("已执行的SQL:" + sql);
}

// 还能获取单个查询的详细统计(比如执行次数、耗时)
QueryStatistics queryStats = stats.getQueryStatistics("FROM User WHERE status = :status");

注意:这个方法会记录所有执行过的SQL语句,如果你只需要特定查询的结果,可以配合字符串过滤使用。

方法3:通过QueryTranslator解析CriteriaQuery生成的SQL

如果你用JPA的CriteriaQuery构建查询,这个方法能帮你直接拿到生成的SQL:

EntityManager em = entityManagerFactory.createEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class);
cq.where(cb.equal(root.get("email"), "test@example.com"));

// 转成Hibernate的Query对象
Session session = em.unwrap(Session.class);
org.hibernate.query.Query<User> hibernateQuery = session.createQuery(cq);

// 获取QueryTranslator并生成SQL
QueryTranslatorFactory translatorFactory = session.getSessionFactory()
        .getServiceRegistry()
        .getService(QueryTranslatorFactory.class);
QueryTranslator translator = translatorFactory.createQueryTranslator(
        hibernateQuery.getQueryString(),
        hibernateQuery.getQueryString(),
        Collections.emptyMap(),
        session.getSessionFactory(),
        null
);
translator.compile(Collections.emptyMap(), false);

// 拿到最终生成的SQL
String generatedSQL = translator.getSQLString();
System.out.println("CriteriaQuery生成的SQL:" + generatedSQL);

小提示

  • 不同Hibernate版本的API可能略有差异,比如Hibernate 6.x中QueryTranslator的使用方式会有调整,记得对应版本查文档。
  • 拦截器会捕获所有SQL(包括增删改查),如果只需要查询语句,可以在onPrepareStatement里通过字符串前缀判断过滤。

内容的提问来源于stack exchange,提问作者Krish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:02:20