In this post, we’ll learn how to track SQL queries, adjust log levels, and debug faster in a Spring Boot application.
· Prerequisites
· Overview
· Enabling SQL Logging
∘ Fine-Grained Logging with Log Levels
· Conclusion
· References
Prerequisites
This is the list of all the prerequisites:
- Spring Boot 3
- Maven 3.6.3 or later
- Java 21
Overview
Debugging database interactions in a Spring Boot application can feel like navigating a maze with a blindfold on. When working with Spring Data JPA and Hibernate, logging isn’t just about printing messages to the console. It’s a window into what’s happening inside your application.
In this post, we’ll explore how to configure, customize, and interpret logging for Hibernate and Spring Data JPA. By the end, you’ll be equipped with practical knowledge to turn logs into powerful diagnostic and monitoring tools that enhance your application’s reliability and performance.
Enabling SQL Logging
spring.jpa.show-sql=true
SQL queries are logged by default by setting the spring.jpa.show-sql property to true. When you set spring.jpa.show-sql=true, Spring Boot passes this configuration to the underlying JPA provider (Hibernate by default), which then prints all SQL commands it executes to the standard output (console).
Hibernate: select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
It prints the SQL statements but does not show the bound parameter values (placeholders (?) will appear without the actual values). It’s generally not recommended to enable show-sql In production environments, excessive logging can negatively impact performance and clutter logs.
spring.jpa.properties.hibernate.format_sql=true
The property spring.jpa.properties.hibernate.format_sql=true tells Hibernate to format the SQL queries it logs, making them much easier to read. Instead of seeing long, single-line SQL statements, you get nicely indented and spaced queries with line breaks.
Hibernate:
select
b1_0.id,
b1_0.description,
b1_0.isbn,
b1_0.page,
b1_0.price,
b1_0.title
from
book b1_0
where
b1_0.id=?
This setting works when .show-sql is enabled. Like show-sql, it’s best to avoid enabling it in production unless needed, as excessive logging can impact performance.
spring.jpa.properties.hibernate.highlight_sql=true
It enables ANSI color codes in Hibernate’s SQL output, making SQL keywords, table names, and other parts of the query visually distinct in the console. It’s essentially “syntax highlighting” for your logged SQL statements.

SQL highlighting works only if your console or IDE log window supports ANSI colors. Otherwise, you might see raw escape codes instead of pretty colors. Like other verbose logging features, it’s mainly for development and debugging, not production.
spring.jpa.properties.hibernate.use_sql_comments=true
It tells Hibernate to include extra comment lines in the generated SQL statements.
These comments typically indicate the context or origin of the query, such as the entity, collection, or operation that triggered it.
@Metaannotation
Sometimes, you need to debug a query based on database performance. The query your database administrator shows you may look VERY different than what you wrote using @Query, or it may look nothing like what you presume Spring Data JPA has generated regarding a custom finder, or if you used query by example.
To make this process easier, you can insert custom comments into almost any JPA operation, whether it’s a query or other operation, by applying the @Meta annotation.
Apply @Meta annotation to repository operations
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
@Meta(comment = "Debug query to retrieve a book by ID")
Book findBookById(Long id);
}
@Meta annotation lets you add a comment that will be inserted into queries before they are sent to the database. It works when use_sql_comments = true
[Hibernate]
/* Debug query to retrieve a book
by
ID */ select
b1_0.id,
b1_0.description,
b1_0.isbn,
b1_0.page,
b1_0.price,
b1_0.title
from
book b1_0
where
b1_0.id=?
spring.jpa.properties.hibernate.generate_statistics=true
It enables Hibernate’s internal statistics tracking. When turned on, Hibernate collects and exposes detailed runtime metrics about how your persistence layer is behaving — things like query counts, cache hits/misses, entity loads, and more.
[Hibernate]
spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=100 select
b1_0.id,
b1_0.description,
b1_0.isbn,
b1_0.page,
b1_0.price,
b1_0.title
from
book b1_0
where
b1_0.id=?
INFO 102129 --- [spring-boot-jpa-hibernate-logging] [ main] i.StatisticalLoggingSessionEventListener : Session Metrics {
24925 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
6745179 nanoseconds spent preparing 1 JDBC statements;
3522200 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
4069191 nanoseconds spent executing 1 flushes (flushing a total of 1 entities and 0 collections);
20127 nanoseconds spent executing 1 pre-partial-flushes;
10052 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections
Collecting statistics adds some overhead. It’s fine for development, testing, or performance profiling, but should generally be disabled in production unless you need it for monitoring. Also, these metrics can be integrated into dashboards via JMX or tools like Micrometer/Prometheus.
spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=5
This property tells Hibernate to log a warning whenever a query takes longer than a given number of milliseconds to execute. The value 5 means log any query that takes more than 5 ms.
Hibernate: select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
INFO 293642 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL_SLOW : Slow query took 8 milliseconds [select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?]
Slow query took 8 milliseconds [select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?]
Fine-Grained Logging with Log Levels
Hibernate generates several categories of logs, each serving different purposes:
- SQL Queries: The actual SQL statements sent to the database
- Parameters: The bound values for query parameters
- Transactions: Transaction lifecycle events
- Cache: Hits and misses for the first and second-level caches
logging.level.org.hibernate.SQL=DEBUG
The org.hibernate.SQL logger is responsible for outputting the raw SQL statements that Hibernate generates and sends to the database, without showing parameter values (those require a separate logger).
DEBUG 104482 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL : select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
Here, we see the generated SQL exactly as Hibernate sends it to the database, but with placeholders (?) for parameters.
logging.level.org.hibernate.orm.jdbc.bind=TRACE
In Hibernate 6 (used by Spring Boot 3 and later), this setting enables parameter binding logs. When set to TRACE, Hibernate logs every value it binds to the placeholders (?) in the generated SQL statements.
DEBUG 106635 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL :
select
b1_0.id,
b1_0.description,
b1_0.isbn,
b1_0.page,
b1_0.price,
b1_0.title
from
book b1_0
where
b1_0.id=?
2025-08-10T23:05:35.579+02:00 TRACE 106635 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.bind : binding parameter (1:BIGINT) <- [1]
logging.level.org.hibernate.engine.transaction=DEBUG
This configuration enables debug-level logging for Hibernate’s transaction management engine.
The org.hibernate.engine.transaction logger category covers the internal events Hibernate triggers when managing database transactions, such as starting, committing, rolling back, or marking transactions for rollback.
DEBUG 115867 --- [spring-boot-jpa-hibernate-logging] [ main] o.h.e.t.internal.TransactionImpl : On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
DEBUG 115867 --- [spring-boot-jpa-hibernate-logging] [ main] o.h.e.t.internal.TransactionImpl : begin
DEBUG 115867 --- [spring-boot-jpa-hibernate-logging] [ main] o.h.e.t.internal.TransactionImpl : committing
In the case of a rollback:
DEBUG 115867 --- [spring-boot-jpa-hibernate-logging] [ main] o.h.e.t.internal.TransactionImpl : rolling back
logging.level.org.hibernate.orm.jdbc.extract=TRACE
It is a Hibernate 6+ logging configuration that enables very detailed logs for JDBC result extraction — the process where Hibernate takes data from the ResultSet returned by the database and maps it to your Java objects (entities, DTOs, etc.).
Use in development when you need deep insight into how Hibernate reads query results, and avoid in production because TRACE logging is expensive and generates a lot of log output.
DEBUG 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL : select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (1:BIGINT) -> [1]
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (2:VARCHAR) -> [netus et malesuada]
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (3:VARCHAR) -> [X4J 5H8]
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (4:INTEGER) -> [62]
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (5:NUMERIC) -> [529.0]
TRACE 286523 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.jdbc.extract : extracted value (6:VARCHAR) -> [arcu. Vestibulum ut]
logging.level.org.hibernate.stat=DEBUG
With Spring Boot 3 + Hibernate 6, it tells Spring Boot to enable Hibernate statistics logging at the DEBUG level.
hibernate.generate_statistics must be true — without it, logging.level.org.hibernate.stat will produce nothing.
spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=DEBUG
DEBUG 289805 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL : select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
DEBUG 289805 --- [spring-boot-jpa-hibernate-logging] [ main] o.h.stat.internal.StatisticsImpl : HHH000117: HQL: [CRITERIA] select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?, time: 30ms, rows: 1
INFO 289805 --- [spring-boot-jpa-hibernate-logging] [ main] i.StatisticalLoggingSessionEventListener : Session Metrics {
43286 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
12090347 nanoseconds spent preparing 1 JDBC statements;
6051813 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
6335860 nanoseconds spent executing 1 flushes (flushing a total of 1 entities and 0 collections);
30012 nanoseconds spent executing 1 pre-partial-flushes;
19497 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections)
}
logging.level.org.hibernate.cache=DEBUG
It controls Hibernate’s second-level and query cache logging, showing when entities/queries are cached, fetched, or evicted with Spring Boot 3 + Hibernate 6.. Useful for diagnosing caching behavior and performance in development, but too verbose for production.
DEBUG org.hibernate.cache - Second-level cache put: entity com.bootlabs.entities.Book id=1
DEBUG org.hibernate.cache - Second-level cache hit: entity com.bootlabs.entities.Book id=1
DEBUG org.hibernate.cache - Query cache put: query=select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id = ?
DEBUG org.hibernate.cache - Query cache miss: query=select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id = ?
logging.level.org.hibernate.orm.results.graph.AST=DEBUG
Hibernate logging category for debugging the construction of DomainResult graphs (the internal structures Hibernate builds to map JDBC results into entities, collections, or composites). Useful for tracing query result interpretation and diagnosing mismatches or inefficiencies in result graph assembly.
DEBUG 314586 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.results.graph.AST : DomainResult Graph:
\-EntityResultImpl [com.bootlabs.entities.Book(2)]
| +-BasicFetch [com.bootlabs.entities.Book(2).description]
| +-BasicFetch [com.bootlabs.entities.Book(2).isbn]
| +-BasicFetch [com.bootlabs.entities.Book(2).page]
| +-BasicFetch [com.bootlabs.entities.Book(2).price]
| \-BasicFetch [com.bootlabs.entities.Book(2).title]
org.hibernate.orm.sql.exec=DEBUG
It is a Hibernate 6 logging category that reports what’s happening during the SQL execution phase — right after a SQL statement is prepared and bound, and just before/after it’s executed on the database.
This logger is part of Hibernate’s new logging structure in Hibernate ORM 6, and it specifically logs low-level execution events, such as:
- Which SQL command is being executed (INSERT, UPDATE, DELETE, SELECT)
- When the SQL execution starts and finishes.
- Row counts returned by DML operations.
- Execution timing (if statistics are enabled
DEBUG 193832 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.orm.sql.exec : Skipping reading Query result cache data: cache-enabled = false, cache-mode = NORMAL
DEBUG 193832 --- [spring-boot-jpa-hibernate-logging] [ main] org.hibernate.SQL : select b1_0.id,b1_0.description,b1_0.isbn,b1_0.page,b1_0.price,b1_0.title from book b1_0 where b1_0.id=?
Conclusion
Well done !!. In this post, we’ve explored how to track SQL queries, adjust log levels, and debug faster in a Spring Boot application.
By understanding these layers, you now have the tools to:
- Make Hibernate’s inner workings visible.
- Diagnose query and performance issues quickly.
- Gain insight into caching, transactions, and SQL execution flow.
Support me through GitHub Sponsors.
Thank you for reading!! See you in the next post.