如何在Spring Boot控制器中获取Java数据查询对应的Hibernate SQL语句?
实现Spring Boot接口获取Hibernate执行的SQL语句
下面提供几种实用的实现方式,根据你的场景选择:
方法1:通过Hibernate StatementInspector拦截并保存SQL
这是最直接的方式,可以在SQL执行时拦截并记录,后续在接口中返回:
- 自定义StatementInspector实现类:
import org.hibernate.resource.jdbc.spi.StatementInspector; public class SqlCaptureInspector implements StatementInspector { private ThreadLocal<String> currentSql = new ThreadLocal<>(); @Override public String inspect(String sql) { currentSql.set(sql); return sql; } public String getCurrentSql() { return currentSql.get(); } public void clear() { currentSql.remove(); } }
- 在Spring Boot配置中注册这个Inspector:
import org.hibernate.jpa.HibernatePersistenceProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import javax.sql.DataSource; @Configuration public class HibernateConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, SqlCaptureInspector sqlInspector) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("your.package.path"); em.setPersistenceProviderClass(HibernatePersistenceProvider.class); // 配置Hibernate属性,添加Inspector em.getJpaPropertyMap().put("hibernate.session_factory.statement_inspector", sqlInspector); return em; } @Bean public SqlCaptureInspector sqlCaptureInspector() { return new SqlCaptureInspector(); } }
- 在控制器/业务方法中获取SQL:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { private final EntityManagerService entityManagerService; private final SqlCaptureInspector sqlInspector; // 构造注入 public UserController(EntityManagerService entityManagerService, SqlCaptureInspector sqlInspector) { this.entityManagerService = entityManagerService; this.sqlInspector = sqlInspector; } @GetMapping("/users") public UserResponse getUsers() { try { var users = entityManagerService.findTable("userTable").getRepository().findAllData(); String executedSql = sqlInspector.getCurrentSql(); // 组装包含数据和SQL的响应 return new UserResponse(users, executedSql); } finally { // 清理ThreadLocal,避免内存泄漏 sqlInspector.clear(); } } } // 自定义响应类 class UserResponse { private List<User> users; private String executedSql; // 构造方法、getter/setter public UserResponse(List<User> users, String executedSql) { this.users = users; this.executedSql = executedSql; } // getter/setter省略 }
方法2:针对自定义Repository方法直接获取SQL
如果你的findAllData是自定义Repository方法,可以通过Hibernate的API直接生成并获取SQL:
假设你的Repository方法基于CriteriaQuery实现,可这样获取SQL:
// 在自定义Repository的findAllData方法中 public List<User> findAllData() { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<User> cq = cb.createQuery(User.class); Root<User> root = cq.from(User.class); cq.select(root); // 获取Hibernate的QueryImpl,进而获取SQL org.hibernate.query.Query<User> query = entityManager.createQuery(cq); String sql = query.unwrap(org.hibernate.query.Query.class).getQueryString(); // 可以将SQL保存到ThreadLocal或者返回给上层 sqlCaptureInspector.inspect(sql); return query.getResultList(); }
方法3:通过日志框架捕获SQL(适合调试或非实时场景)
如果只是需要获取SQL,也可以通过配置Hibernate日志,再将日志内容捕获到内存中供接口返回,但这种方式复杂度较高,仅推荐调试场景使用:
在application.properties中配置日志:
# 输出Hibernate生成的SQL logging.level.org.hibernate.SQL=DEBUG # 输出SQL参数(可选) logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
之后可以自定义日志Appender,将日志内容收集到内存中,在接口中读取。需注意处理日志过滤和线程隔离问题。
内容的提问来源于stack exchange,提问作者Diogo Alpendre
相关产品推荐
相关产品推荐

