Use logback to log SQL parameters in Spring JdbcTemplate - spring

I'm using Logback with Spring JdbcTemplate to log my SQL queries. My configurations contains next line:
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG" />
But this logs only query with wildcards ? without list of parameters.
Here on SO I found a few answers how to achieve parameters logging with log4j. But I don't want to switch to log4j.
So how can I receive parameters list for JdbcTemplate with Logback?
Edit
Actually, I'm using NamedParameterJdbcTemplate, if it matters.

Try this
<logger name="org.springframework.jdbc.core.StatementCreatorUtils" level="TRACE" />
this will show log:
Setting SQL statement parameter value: column index 1, parameter value [1234], value class [java.lang.Integer], SQL type unknown

I usually prefer handling SQL statement logging at the DataSource or JDBC driver level.
I use BoneCP DataSource/Connection Pool library, which include support for statement logging via SLF4J and many other usefull features.
If changing your DataSource/Connection Pool library is not an option, maybe you can use log4jdbc which works as a proxy jdbc driver, which logs statements to SLF4J before calling the actual jdbc driver that talks to the database.

We can use as follow :
org.hibernate.type.descriptor.sql.
See Link: https://thorben-janssen.com/hibernate-logging-guide/

Related

How to use Spring environment values from config server in Logstash Encoder of Logback

I would like to use Spring environment values as custom fields in the Logstash encoder of a Logback appender.
There is a general configuration tag to use properties
<property resource="logstash.properties" />
And there is a special configuration tag from Spring for this purpose
<springProperty name="appEnv" source="environment"/>
The properties of both tags can then be used in the custom fields of the Logstash encoder
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"application.environment":"${appEnv}"</customFields>
</encoder>
Problem is, as far as I understand, that this only works under certain circumstances. The problem is probably that Logback has already finished configuring when the Spring environment is built.
It seems to work when
The property is local and static (available on configuration time)
The property is in bootstrap.properties
It seems NOT to work when
The property is dynamic as when retrieved from Spring config server
My property values delivered from config server are null when Logback is configured and therefore the log shows them as appEnv_IS_UNDEFINED for a property called appEnv.
Because most examples just use the spring.application.name this seems to be mostly unnoticed.
To solve the timing problem, I searched for a way to reload the Logback configuration onApplicationEvent. I found this answer that confirms my problem and offers a skeleton solution.
I found other solutions where the Logback appender that uses the Logstash encoder is completely programmatically built and added to the LoggerContext.
However, I wonder if there is also a way to stick with the XML configuration of the appender and "just reload" the config programmatically when the Spring environment is ready. How would I do this?
I found this answer to do the reload, but it does not work for my case. The appEnv_IS_UNDEFINED continue to appear in the log file.
I was able to solve my problem by implementing a Spring ApplicationContextInitializer.
In the called initialize method I can access my Logback Appender and Encoder via RootLogger.
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
RollingFileAppender jsonFileAppender = (RollingFileAppender) rootLogger.getAppender(LOGSTASH_APPENDER_NAME);
LogstashEncoder encoder = (LogstashEncoder) jsonFileAppender.getEncoder();
From the LogstashEncoder, I can get the customFields
String customFields = encoder.getCustomFields();
And there I found the unresolved properties in the JSON String as expected
{"application.environment":"appEnv_IS_UNDEFINED"}
Since I can get the built Spring Environment from the passed ApplicationContext
springEnvironment = applicationContext.getEnvironment();
I can match unresolved properties with the Regex (\w+)_IS_UNDEFINED and replace them with the real value from the Spring Environment.
Surprisingly, I do not need to reload or restart anything. It is sufficent to just set the fixed customFields on the Encoder. Immediately after, the Log messages contain the correct values.
encoder.setCustomFields(fixedCustomFields);
With this Initializer in place, I can fully configure my appender and the LogstashEncoder in logback-spring.xml or an included file.

Getting DDL Before Updating the Schema in Hibernate Spring Applications

In a Spring-Hibernate application, hibernate.show_sql=true in log4j property file is enough to show to hibernate generated query. But what we have to do if we need the actual sql query.(For production environment i need to observer and verify the query before updating the schema).
What i am going to do is, after the first schema generation in production( by hibernate itself) i dont want hibernate to update the schema(DDL).I want to hijack the alter, update (DDL) queries and after verification i would like to run those scripts manually in DB.
Is there any approach to do that?
Hibernate has build-in a function to enable the logging of all the generated SQL statements to the console. You can enable it by add a show_sql property in the Hibernate configuration file hibernate.cfg.xml. This function is good for basic troubleshooting, and to see what’s Hibernate is doing behind.
hibernate.cfg.xml
show_sql
Enable the logging of all the generated SQL statements to the console
<property name="show_sql">true</property>
format_sql
Format the generated SQL statement to make it more readable, but takes up more screen space.
<property name="format_sql">true</property>
use_sql_comments
Hibernate will put comments inside all generated SQL statements to hint what’s the generated SQL trying to do
<property name="use_sql_comments">true</property>
log4j.properties
log4j.logger.org.hibernate=INFO, hb
log4j.logger.org.hibernate.SQL=DEBUG ## is equivalent to hibernate.show_sql=true
log4j.logger.org.hibernate.type=TRACE ## allows you to see the binding parameters
log4j.logger.org.hibernate.hql.ast.AST=info
log4j.logger.org.hibernate.tool.hbm2ddl=warn
log4j.logger.org.hibernate.hql=debug
log4j.logger.org.hibernate.cache=info
log4j.logger.org.hibernate.jdbc=debug
log4j.appender.hb=org.apache.log4j.ConsoleAppender
log4j.appender.hb.layout=org.apache.log4j.PatternLayout
log4j.appender.hb.layout.ConversionPattern=HibernateLog --> %d{HH:mm:ss} %-5p %c - %m%n
log4j.appender.hb.Threshold=TRACE
log4j.logger.org.hibernate.tool.hbm2ddl=debug
To print the bind parameters as well, add the following to your log4j.properties file:
log4j.logger.net.sf.hibernate.type=debug
Add the following configurations in log4j.properties file
logs the SQL statements
log4j.logger.org.hibernate.SQL=debug
Logs the JDBC parameters passed to a query
log4j.logger.org.hibernate.type=trace
Enable the show sql property in hibernate configuration file as follows.
<property name="show_sql">true</property>
For more details, check the post

dynamically setting DataSource properties for Spring jdbc

I'm using spring jdbc and I want my application to connect to different DBMS as oracle,mySQL, SAS etc.
the application should work on different systems, so the connection properties are not priorly known.
Ideally, the user will be able to select connection type from a list and then set the connection properties (username,password...)
Can you please help me :)
Have a look at this post: http://examples.javacodegeeks.com/enterprise-java/spring/jdbc/spring-jdbctemplate-example/
There you can see the normal jdbctemplate use. As you can see the dao has got the datasource injected: you can basically do the same, but you need not to set the org.springframework.jdbc.datasource.DriverManagerDataSource properties in the applicationContext.xml. You will do it at runtime according to user choice. That basically means all the daos have to get the datasource needed params in input.
Hope this helps.

How to connect to HSQL which Spring creates when jdbc:embedded-database is used?

I have a HSQL database which Spring automatically creates for me:
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:scheme.sql" /
</jdbc:embedded-database>
And now I want to connect to this database. My question is how to do this, because I don't known which address I should use.
This embedded HSQL database is all-in-memory and in-process, therefore accessible only from the Spring Java process. If you want to access the database from another tool as well, for example to check the contents with a database manager, you can start an HSQLDB server with an all-in-memory instance, then connect to the server from Spring and other tools.
This is covered in the HSQLDB Guide http://hsqldb.org/doc/2.0/guide/listeners-chapt.html
The server is started with this command:
java -cp ../lib/hsqldb.jar org.hsqldb.Server --database.0 mem:test --dbname.0 test
You need to create a Spring data source with username "SA" and password "". The database driver and URL (from the same machine) to configure the Spring data source are:
org.hsqldb.jdbcDriver
jdbc:hsqldb:hsql://localhost/test
I recomend you to use external Database, but just in case if you want to use HSQL, then this may will help you http://java.dzone.com/articles/spring-3-makes-use-embedded-easy
Embedded-database is an in memory DB and Spring supports HSQL, H2, and Derby . You could go to their respective site for the connection details .
For H2 see here .
For HSQL see here and here.
As far as I understand , the
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:scheme.sql" /
</jdbc:embedded-database>
uses an in-memory DB and so is not accessible externally . You'll be able to access this within the same VM and same class loader .
You can connect to the embedded database in the normal fashion, (SQL Developer, SQL Explorer etc); I used my debugger to look at the URL property in the embedded database bean I created with Spring, in your case dataSource. I would think your url would be something along the lines of jdbc:hsqldb:mem:dataSource.
For some people a sufficient solution would be to use the h2 console - as described here:
spring boot default H2 jdbc connection (and H2 console)
You must only remember to set hsqldb drivers where needed. This way the database doesn't have to be started separately. You also don't have to install any additional software to browse it.
you can do like this
final ApplicationContext ctx = new ClassPathXmlApplicationContext("dao-context.xml");
final DataSource dataSource = (DataSource)ctx.getBean("dataSource");
final Connection conn = dataSource.getConnection();

How to use HSQLDB as a datasource in Websphere Application Server?

I try to set up a local development infrastructure and I want to use HSQLDB as a datasource with my WAS 6.1. I already know that I have to use Apache DBCP to get a connection pooling, but I'm stuck when my application tries to get the first connection.
What I've done
In WAS I created a JDBC provider with the class org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS and removed everything from the classpath input field. Then I put commons-dbcp.jar, commons-pool.jar and hsqldb.jar in MYAPPSERVERDIRECTORY/lib/ext.
Then I created a new datasource with that provider. I added the following custom properties:
driver=org.hsqldb.jdbc.JDBCDriver
url=jdbc:hsqldb:file:///C:/mydatabase.db;shutdown=true
user=SA
password=
My Problem
When I run my application and the first connection to the database is made, I get the following exception:
---- Begin backtrace for Nested Throwables
java.sql.SQLException: No suitable driverDSRA0010E: SQL-Status = 08001, Fehlercode = 0
at java.sql.DriverManager.getConnection(DriverManager.java:592)
at java.sql.DriverManager.getConnection(DriverManager.java:196)
at org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS.getPooledConnection(DriverAdapterCPDS.java:205)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:918)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:955)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1437)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1089)
at com.ibm.ejs.j2c.FreePool.createManagedConnectionWithMCWrapper(FreePool.java:1837)
at com.ibm.ejs.j2c.FreePool.createOrWaitForConnection(FreePool.java:1568)
at com.ibm.ejs.j2c.PoolManager.reserve(PoolManager.java:2338)
at com.ibm.ejs.j2c.ConnectionManager.allocateMCWrapper(ConnectionManager.java:909)
at com.ibm.ejs.j2c.ConnectionManager.allocateConnection(ConnectionManager.java:599)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:439)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:408)
Any tips on this? I suspect I'm using a wrong class from hsqldb, or maybe my JDBC url is wrong...
In the example given in BDCP docs, the org.hsqldb.jdbcDriver class is used as the driver. The org.hsqldb.jdbc.JDBCDriver is supported only in HSQLDB 2.x, but the other class is supported by all versions of HSQLDB.

Resources