marschall / jfr-jdbctemplate

an implementation of Spring JdbcTemplate that generates Flight Recorder events

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JFR JdbcTemplate Maven Central Javadocs

An implementation of Spring JdbcTemplate that generates Flight Recorder events.

This project requires Java 11 based on OpenJDK or later.

<dependency>
  <groupId>com.github.marschall</groupId>
  <artifactId>jfr-jdbctemplate</artifactId>
  <version>2.0.0</version>
</dependency>

Versions 1.x are intended for Spring 5.x / Java 11, versions 2.x are intended for Spring 6.x / Java 17.

Flight Recording of a JUnit Test

Compared to approaches based on DataSource an approach based on JdbcTemplate has the advantage that it captures a complete database interaction. For example if you process many rows the initial PreparedStatement#execute() might be fast but most of the time may be spent in ResultSet#next(). A JdbcTemplate based approach generates a single JFR event for the entire interaction that involves several JDBC method invocations.

Spring Class JFR Class
org.springframework.jdbc.core.JdbcOperations com.github.marschall.jfr.jdbctemplate.JfrJdbcOperations
org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations com.github.marschall.jfr.jdbctemplate.JfrNamedParameterJdbcOperations

Reported Attributes

operationName
The name of the execute JDBC operation, this corresponds to the method name on JdbcOperations/JdbcTemplate.
query
The SQL query string passed to the JDBC driver. May be missing especially if custom org.springframework.jdbc.core.PreparedStatementCreator fail to implement org.springframework.jdbc.core.SqlProvider.
rowCount
In the case of a SELECT the number of rows returned. In the case of an UPDATE or DELETE the number of rows affected. -1 for a statement that does not return anything like a DDL. -2 when no information about the number of rows is available.

Overhead

We try to keep overhead to a minimum and have no additional allocations besides the JFR events. Besides the overhead of the event the only additional overhead is:

  • a wrapper around JdbcTemplate
  • a few instanceof operations and casts
  • a finally block
  • a capturing lambda for #queryForStream methods to record Stream#close as the end time of the event
  • a small wrapper around every RowCallbackHandler

We assume org.springframework.jdbc.core.SqlProvider#getSql() is a simple getter.

Usage

@Configuration
public class JdbcConfiguration {

   @Autowired
   private DataSource dataSource;

   @Bean
   public JdbcOperations jdbcOperations() {
     return new JfrJdbcOperations(new JdbcTemplate(this.dataSource));
   }

   @Bean
   public NamedParameterJdbcOperations namedParameterJdbcOperations() {
     return new JfrNamedParameterJdbcOperations(new NamedParameterJdbcTemplate(this.jdbcOperations()));
   }

}

You need something like the following JVM options to run Flight Recorder

-XX:StartFlightRecording:filename=recording.jfr
-XX:FlightRecorderOptions:stackdepth=128

Limitations

  • When the SQL query is not provided as a String but as a PreparedStatementCreator or CallableStatementCreator it has to implement SqlProvider for the query string to show up in the flight recording.
  • JdbcTemplate#query(PreparedStatementCreator, PreparedStatementSetter, ResultSetExtractor) is not available because it is defined on JdbcTemplate and not JdbcOperations.
  • Several spring-jdbc classes AbstractJdbcCall, SimpleJdbcCall, StoredProcedure, RdbmsOperation, AbstractJdbcInsert, SimpleJdbcInsert but also JdbcTestUtils and JdbcBeanDefinitionReader require a JdbcTemplate and do not work with JdbcOperations. We have a pull request open for this but it has not been merged yet.
  • JdbcOperations#execute(ConnectionCallback) can not provide any insight into what is executed inside, that would require integration with marschall/jfr-jdbc

About

an implementation of Spring JdbcTemplate that generates Flight Recorder events


Languages

Language:Java 100.0%