How can I log SQL statements in Spring Boot? - java

I want to log SQL statements to a file.
I have the following properties in application.properties:
spring.datasource.url=...
spring.datasource.username=user
spring.datasource.password=1234
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
security.ignored=true
security.basic.enabled=false
logging.level.org.springframework.web=INFO
logging.level.org.hibernate=INFO
logging.file=c:/temp/my-log/app.log
When I run my application,
cmd> mvn spring-boot:run
I can see SQL statements in the console, but they don't appear in app.log. The file contains only basic logs from Spring.
What should I do to see SQL statements in the log file?

Try using this in your properties file:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

This works for standard output too:
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
To log values:
logging.level.org.hibernate.type=trace
Just add this to application.properties.

This works for me (YAML):
spring:
jpa:
properties:
hibernate:
show_sql: true
format_sql: true
logging:
level:
org:
hibernate:
type: trace

Settings to avoid
You should not use this setting:
spring.jpa.show-sql=true
The problem with show-sql is that the SQL statements are printed in the console, so there is no way to filter them, as you'd normally do with a Logging framework.
Using Hibernate logging
In your log configuration file, if you add the following logger:
<logger name="org.hibernate.SQL" level="debug"/>
Then, Hibernate will print the SQL statements when the JDBC PreparedStatement is created. That's why the statement will be logged using parameter placeholders:
INSERT INTO post (title, version, id) VALUES (?, ?, ?)
If you want to log the bind parameter values, just add the following logger as well:
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="trace"/>
Once you set the BasicBinder logger, you will see that the bind parameter values are logged as well:
DEBUG [main]: o.h.SQL - insert into post (title, version, id) values (?, ?, ?)
TRACE [main]: o.h.t.d.s.BasicBinder - binding parameter [1] as [VARCHAR] - [High-Performance Java Persistence, part 1]
TRACE [main]: o.h.t.d.s.BasicBinder - binding parameter [2] as [INTEGER] - [0]
TRACE [main]: o.h.t.d.s.BasicBinder - binding parameter [3] as [BIGINT] - [1]
Using datasource-proxy
The datasource-proxy OSS framework allows you to proxy the actual JDBC DataSource, as illustrated by the following diagram:
You can define the dataSource bean that will be used by Hibernate as follows:
#Bean
public DataSource dataSource(DataSource actualDataSource) {
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
loggingListener.setQueryLogEntryCreator(new InlineQueryLogEntryCreator());
return ProxyDataSourceBuilder
.create(actualDataSource)
.name(DATA_SOURCE_PROXY_NAME)
.listener(loggingListener)
.build();
}
Notice that the actualDataSource must be the DataSource defined by the connection pool you are using in your application.
Next, you need to set the net.ttddyy.dsproxy.listener log level to debug in your logging framework configuration file. For instance, if you're using Logback, you can add the following logger:
<logger name="net.ttddyy.dsproxy.listener" level="debug"/>
Once you enable datasource-proxy, the SQL statement are going to be logged as follows:
Name:DATA_SOURCE_PROXY, Time:6, Success:True,
Type:Prepared, Batch:True, QuerySize:1, BatchSize:3,
Query:["insert into post (title, version, id) values (?, ?, ?)"],
Params:[(Post no. 0, 0, 0), (Post no. 1, 0, 1), (Post no. 2, 0, 2)]

Please use:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
spring.jpa.show-sql=true

If you have a logback-spring.xml file or something like that, add the following code to it:
<logger name="org.hibernate.SQL" level="trace" additivity="false">
<appender-ref ref="file" />
</logger>
That works for me.
To get bind variables as well:
<logger name="org.hibernate.type.descriptor.sql" level="trace">
<appender-ref ref="file" />
</logger>

For the SQL Server driver (Microsoft SQL Server JDBC Driver), try using:
logging.level.com.microsoft.sqlserver.jdbc=debug
in your application.properties file.
My personal preference is to set:
logging.level.com.microsoft.sqlserver.jdbc=info
logging.level.com.microsoft.sqlserver.jdbc.internals=debug
You can look at these links for reference:
Tracing driver operation
“How-to” Guides, 7. Logging

Translated accepted answer to YAML works for me
logging:
level:
org:
hibernate:
SQL:
TRACE
type:
descriptor:
sql:
BasicBinder:
TRACE

According to documentation it is:
spring.jpa.show-sql=true # Enable logging of SQL statements.

Log in to standard output
Add to application.properties
### To enable
spring.jpa.show-sql=true
### To make the printing SQL beautify
spring.jpa.properties.hibernate.format_sql=true
This is the simplest way to print the SQL queries, though it doesn't log the parameters of prepared statements.
And it’s not recommended since it’s not such as optimized logging framework.
Using a logging framework
Add to application.properties
### Logs the SQL queries
logging.level.org.hibernate.SQL=DEBUG
### Logs the prepared statement parameters
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
### To make the printing SQL beautify
spring.jpa.properties.hibernate.format_sql=true
By specifying the above properties, log entries will be sent to the configured log appender, such as log-back or Log4j.

We can log SQL statements using two approaches in Spring boot:
1: using logger
2: standard approach
For logger
You should add this line to application.properties file:
logging.level.org.hibernate.SQL=DEBUG
Standard Approach
You should add these lines in application.properties file:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

If you want to view the actual parameters used to query you can use
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql=TRACE
Then notice that actual parameter value is shown as binding parameter...:
2018-08-07 14:14:36.079 DEBUG 44804 --- [ main] org.hibernate.SQL : select employee0_.id as id1_0_, employee0_.department as departme2_0_, employee0_.joining_date as joining_3_0_, employee0_.name as name4_0_ from employee employee0_ where employee0_.joining_date=?
2018-08-07 14:14:36.079 TRACE 44804 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [Tue Aug 07 00:00:00 SGT 2018]

We can use any one of these in the application.properties file:
spring.jpa.show-sql=true
Example:
//Hibernate: select country0_.id as id1_0_, country0_.name as name2_0_ from country country0_
or
logging.level.org.hibernate.SQL=debug
Example:
2018-11-23 12:28:02.990 DEBUG 12972 --- [nio-8086-exec-2] org.hibernate.SQL : select country0_.id as id1_0_, country0_.name as name2_0_ from country country0_

For hibernate 6:
it is:
spring.jpa.properties.hibernate.show_sql=true
logging.level.org.hibernate.orm.jdbc.bind = trace

You can simply add the below lines in application.properties for stdout SQL queries:
spring.jpa.properties.hibernate.show_sql=true

Use this code in the file application.properties:
# Enable logging for configuration troubleshooting
logging.level.org.hibernate.SQL=DEBUG
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

If you're having trouble with this setting and it seems to work sometimes and not other times - consider if the times where it doesn't work are during unit tests.
Many people declare custom test-time properties via the #TestPropertySources annotation declared somewhere in your test inheritance hierarchy. This will override whatever you put in your application.properties or other production properties settings so those values you're setting are effectively being ignored at test-time.

Putting spring.jpa.properties.hibernate.show_sql=true in application.properties didn't help always.
You can try to add properties.put("hibernate.show_sql", "true"); to the properties of the database configuration.
public class DbConfig {
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
entityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSource") DataSource dataSource
) {
Map<String, Object> properties = new HashMap();
properties.put("hibernate.hbm2ddl.auto", "validate");
properties.put("hibernate.show_sql", "true");
return builder
.dataSource(dataSource)
.packages("com.test.dbsource.domain")
.persistenceUnit("dbsource").properties(properties)
.build();
}

You just need to set spring.jpa.show-sql=true in application.properties.
For example, you may refer to ConfigServerRepo/application.yaml.

In my YAML file:
logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql: TRACE
Spring Boot version: 2.3.5.RELEASE

The basic way is to add the following lines in your application.properties. This will enable Spring Boot to log all your SQL queries that get executed:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
The second line is used to beautify the SQL statements.
If you want to use loggers, you can use the following lines:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
The second line is used to print all the parameters that get bound with your queries.

Add these in the properties. Quoting Hibernate Show SQL:
# Show SQL statement
logging.level.org.hibernate.SQL=debug
# Show SQL values
logging.level.org.hibernate.type.descriptor.sql=trace

If you are using JdbcTemplate, add the below in application.properties file to log SQL and parameter values.
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=TRACE

Related

Spring boot parameter update model Database don't work

i set the value to update value so that a table will be created in the database automatically corresponding to defined data model.
But it does not work, what it wrong with my properties ?
Database: Mysql
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
server.port=8081
server.servlet.session.timeout=1200
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
spring.datasource.username= root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.storage.storage_engine=innodb
spring.security.user.name="root"
spring.security.user.password="123"
spring.resources.add-mappings=true
java.sql.SQLSyntaxErrorException: Table 'test.files' doesn't exist
What genereted conflict with "spring.jpa.hibernate.ddl-auto=update"
Make sure the database connection string is valid.
Try changing spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
The name of your database is "test" but is it really?

Database did not create with annotation on entity class

I created my entity classes and annotations normally, but hibernate can not generate the tables in my database.
##DataSource settings
spring.datasource.url=jdbc:oracle:thin:#//localhost:1521/BD_GESTION_OPERATION?createDatabaseIfNotExist=true&userSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=system
spring.datasource.password=SeCret
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
##Disabling spring basic security
security.basic.enabled=false
##Start up port
server.port=8082
##Specify DBMS
spring.jpa.database=ORACLE
##Show/Hide SQL queries
spring.jpa.show-sql=false
##Hibernate DDL Auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto=update
##Naming strategy
spring.jpa.hibernate.naming.strategy=org.hibernate.cfg.ImprovedNamingStrategy
##Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
Delete old tables. In your application.properties, set property like that (this is default, even you no need declaring it)
spring.jpa.hibernate.ddl-auto=create-drop
You also want to try
spring.jpa.hibernate.ddl-auto=create
Reference https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-initialize-a-database-using-hibernate

Is it possible to set hibernate.show_sql for Query programmatically

I use Hibernate with Spring and initialize it with LocalContainerEntityManagerFactoryBean bean with hibernate.show_sql=false in JpaProperties of it. So, I disabled SQL output of Hibernate, but I want to print SQL only for some Query, that I want to debug.
Is it possible to set hibernate.show_sql for Query programmatically, to don't print all SQL queries at runtime, but print them only for some Query?
And no, it's not a duplicate. Because, everything, that explained in suggested answer is already done in my app. I need to enable SQL logging not for all Queries in my app, but only for one Query.

How to use Hibernate with multiple databases on a single server

Our application allows our customer to have multiple databases, all running on one instance of the database server.
For example, databases might be dbcommon, dbLive, dbStaging, dbUAT, dbDev, dbSandbox. The common database and the Production database always exists, but the others are optional (and there is no limit). In dbcommon there is a table that tells us all the databases....so that's where I would need to start. The tables in common are different from the others, and the others all have the same schema (subscriber data)
Using Hibernate, how can I dynamically create/use a connection to either Live or Staging (or any of the others)? I am using Spring if that helps.
I have come across answers that suggest creating different connections in configuration, but because the number of subscriber databases can vary (per install, not while the app is running), this isn't an option for me.
As I discovered after posting this question, and as the user manish suggested, Hibernate's Multi Tenancy support (using the Database MultiTenancyStrategy) works for me. I had to piece together a solution using various resources (listed below).
http://www.ticnfae.co.uk/blog/2014/07/16/hibernate-multi-tenancy-with-spring/
Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1
Multi-Tenancy with Spring + Hibernate: "SessionFactory configured for multi-tenancy, but no tenant identifier specified"
I'm still looking for a way to be able to reference the common (shared) database at the same time as tenant databases...and will try to add that to this answer when complete.
The simplest way I can see to do this is to manage everything via profiles in Spring.
I accomplished this by using application.yml. I'm also using a Hikari connection pool, but that doesn't effect the configuration too much.
Here is an example of a application.yml with 3 profiles listed, and I've defined two of them as an example.
spring:
profiles:
include: dev,test,production
active: dev
---
spring:
profiles: dev
oms:
omsDataSource:
driverClassName: com.informix.jdbc.IfxDriver
jdbcUrl: jdbc:informix-sqli://devdb:9000/hol:INFORMIXSERVER=m_tcp_1;client_deve=en_US.8859-1;db_deve=en_US.8859-1;LOBCACHE=-1
password: oms
username: oms
connectionTestQuery: select count(*) from systables
maximumPoolSize: 5
---
spring:
profiles: test
oms:
omsDataSource:
driverClassName: com.informix.jdbc.IfxDriver
jdbcUrl: jdbc:informix-sqli://testdb:9000/hol:INFORMIXSERVER=m_tcp_1;client_deve=en_US.8859-1;db_deve=en_US.8859-1;LOBCACHE=-1
password: oms
username: oms
connectionTestQuery: select count(*) from systables
maximumPoolSize: 5
In my DB config class, I set the JPA repositories, and tell it what entityManager to use. I also setup the configuration properties to pull frmo the application.yml . This means it will swap out the details based on the profile the app is using on launch.
#EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryOms",
transactionManagerRef = "transactionManagerOms",
basePackages= "persistence.oms")
#Configuration
#ConfigurationProperties(prefix = "oms.omsDataSource")
public class omsDbConfig extends HikariConfig {
//This will automatically fill in the required fields from the application.yml.
#Bean
public HikariDataSource orcaDataSource() throws SQLException {
return new HikariDataSource(this);
}
//I use that datasource to define my entityMangerFactory
#Bean(name = "entityManagerFactoryOms")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryOrca() throws SQLException {
JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
Properties props = new Properties();
props.setProperty("hibernate.dialect","org.hibernate.dialect.InformixDialect");
LocalContainerEntityManagerFactoryBean emfb =
new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(orcaDataSource());
emfb.setPackagesToScan("persistence.oms");
emfb.setJpaProperties(props);
emfb.setJpaVendorAdapter(adapter);
return emfb;
}
}
The entities and repositories are defined normally, there's nothing special there. The DB will switch connection based on whatever profile I tell it to run.
I just switch out the active profile in the application.yml to whichever one I need.
Safety note: Define a production profile, don't have production as a default profile.

Set root logging level in application.yml

I used an application.properties with Spring Boot (1.3 M1) and started to translate it into a yaml file because it grew more and more complex.
But I have problems translating this into yaml:
logging.level.*=WARN
logging.level.com.filenet.wcm=ERROR
logging.level.de.mycompany=DEBUG
The last two lines are easily translated into this:
logging:
level:
com.filenet.wcm: ERROR
de.mycompany: DEBUG
But how to add the values for the root logging level ? These two approaches failed:
Failed approach 1:
logging:
level: WARN
com.filenet.wcm: ERROR
de.mycompany: DEBUG
Failed approach 2:
logging:
level:
star: WARN
com.filenet.wcm: ERROR
de.mycompany: DEBUG
I read the docs, searched stackoverflow and googled but did not find an example for a valid syntax.
You can use ROOT to configure the root logging level:
logging:
level:
ROOT: DEBUG
If you want level by package, you can use this syntax :
logging:
level:
org.springframework.web: DEBUG
guru.springframework.controllers: DEBUG
org.hibernate: DEBUG
org: INFO
You can even use your classname to configure logging level:
logging:
level:
com.yourorganization.Yourclass: DEBUG
It's an old question, but I just had this problem.
While setting
org.springframework.web: debug
or
org.hibernate: debug
works fine, if you want to do the same for your project files (setting level per package), you have to use wildcards. So, for the example in the question, it would be:
logging:
level:
root: WARN
com.filenet.wcm.*: ERROR
de.mycompany.*: DEBUG
Alternatively, you can set the logging level per class without using wildcards, as shown in torina's answer.
You can log incoming request by creating CommonsRequestLoggingFilter and adding
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
to application.properties file as explained in detail in this link - https://www.baeldung.com/spring-http-logging
#Configuration
public class RequestLoggingFilterConfig {
#Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter
= new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(10000);
filter.setIncludeHeaders(false);
filter.setAfterMessagePrefix("REQUEST DATA : ");
return filter;
}
}

Categories