Over a million developers have joined DZone.
Silver Partner

Monitoring Declarative Transactions in Spring

· Java Zone

Declarative transaction management is arguably one of the most useful and widely used features of the Spring Framework. It allows sophisticated control over transactions with only a few lines of configuration. A typical application need only to add an @Transactional annotation to a given method, plus drop in a <tx:annotation-driven/> and a few other tags in a Spring configuration file to achieve reliable transaction management.

As easy as it is to configure Spring Framework to manage transactions, it is almost as easy to misconfigure such that transactions are not managed at all. Because Spring uses a non-invasive approach to starting and ending transactions, it can be difficult to tell whether a given section of code is operating inside a managed transaction. I once reviewed an application for a client that was having database problems in production; these were eventually traced to a complete lack of transactional integrity. The root problem (you guessed it): misconfiguration of Spring transaction management. The application had been running for a year in this condition.

So the question is: how can we reliably detect whether or not application logic is running inside managed transactions. This article explores several possibly paths and develops the most appropriate solution.

Possible Solutions

Check from Code

Probably the most straight-forward way to verify whether the business logic is in a transaction is to add some code that tests for this condition. Spring Framework provides a class that's suitable for this purpose: TransactionSynchronizationManager. Typical usage might look like the following:

public void invokeInsert() throws SQLException {
assert TransactionSynchronizationManager.isActualTransactionActive();
logger.info("invoking insert");...

The major detraction from this approach is the invasiveness of the check. Every class that needs verification of transaction management would have to be modified to include the new check. This not only implies doing some work, but also means that verification is limited to situations where the application can be redeployed with the new changes. In some cases the lead time for an full deployment cycle will rule out this approach all together.

Empirical Test

Another approach to verifying transaction management is to induce application failure during transaction processing, then see if changes were in fact rolled back by the resource manager (i.e., database). Failure might be induced by running the application through a debugger, stopping at various critical points and tweaking values such that the application throws an exception and aborts the supposed transaction. Other scenarios are common, such as detaching the application server from the network, killing the database server, etc.

This is the ultimate test for a system's transactional behavior, but there are a few problems:

  • you really can't perform this test in a database that has valuable information. If the business logic really isn't under transaction management then the database may be corrupted.
  • unless the application is controlled by a debugger, it may be difficult to get pinpoint control over where the failure condition occurs
  • achieving any kind of significant code coverage involves a lot of testing
  • access for the tester may be a problem for some production systems.
  • approach is a point in time measurement; it may need to be repeated as the application evolves

Logging Decoration

If an application is using a logging framework already, it may make sense to plug into the logging framework to indicate whether the calling code is wrapped in a transaction. Each message that the application currently emits could be decorated to indicate whether a transaction is present:

INFO: [main -] creating table TEST
Nov 18, 2008 6:24:50 PM com.skillcorp.transactionlogger.jdklog.JdbcQueryBean invokeInsert
INFO: [main +] invoking insert
Nov 18, 2008 6:24:50 PM com.skillcorp.transactionlogger.jdklog.JdbcQueryBean invokeInsertINFO: [main +] inserts complete
Nov 18, 2008 6:24:50 PM com.skillcorp.transactionlogger.jdklog.JdbcQueryBean invokeInsert
INFO: [main +] throwing exception to abort transactionNov 18, 2008 6:24:50 PM com.skillcorp.transactionlogger.jdklog.JdbcQueryBean invokeQuery
INFO: [main -] invoking query

In the log output above, each message has been decorated with a '+' or '-' to indicate the presence of a transaction. The message invoking insert, for instance, indicates that the business logic was in a transaction (+) driven by a thread named 'main'. The benefits of this approach, while restricted to applications that actually log messages, include:

  • non-invasive. Can be applied to an existing application that already uses logging
  • comprehensive. Easily configurable to cover all transactional code in the app
  • removable. Incurs no performance penalty when removed from logging configuration
  • easily testable/verifiable. Results are present in the application's log output

Designing a Solution with Logging

Class Loading

A transaction logging solution can be easily implemented for either Log4J or Java Logging, provided we watch out for class loading issues. Java Logging and typically Log4J are installed in a low-level class loader that does not have direct access to the Spring Framework classes needed to observe transaction status. Fortunately for us, Spring classes are accessible at runtime from the 'context class loader' attached to each thread. Using the context class loader and a little reflection, it's possible to invoke methods on TransactionSynchronizationManager to determine transaction status. The code below demonstrates how to determine the status for the current thread via reflection:

public class TransactionIndicatingUtil {
private final static String TSM_CLASSNAME = "org.springframework.transaction.support.TransactionSynchronizationManager";

public static String getTransactionStatus(boolean verbose)
String status = null;

try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (contextClassLoader != null)
Class tsmClass = contextClassLoader.loadClass(TSM_CLASSNAME);
Boolean isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
if (!verbose) {
status = (isActive) ? "[+] " : "[-] ";
else {
String transactionName = (String) tsmClass.getMethod("getCurrentTransactionName", null).invoke(null, null);
status = (isActive) ? "[" + transactionName + "] " : "[no transaction] ";
status = (verbose) ? "[ccl unavailable] " : "[x ]";
} catch (Exception e) {
status = (verbose) ? "[spring unavailable] " : "[x ]";
return status;
The method TransactionIndicatingUtil .getTransactionStatus above is suitable for our logging solution because does not directly reference the Spring Framework code. The next step is to invoke it from within the logging framework.

Plugging into Log4J

The ideal point to plug into the Log4J framework is at the Filter level. Filters intercept logging messages before they reach an Appender in Log4J (i.e., ConsoleAppender, FileAppender). We can create a filter that adds information to the MappedDiagnosticContext, or MDC, of the logging event. The MDC is essentially a Map of name/value pairs that are available to an Appender for output. Here's our filter implementation that adds a 'xaName' and 'xaStatus' property to the MDC: 

import static com.skillcorp.transactionlogger.TransactionIndicatingUtil.*;
public class TransactionIndicatingFilter extends Filter {
public int decide(LoggingEvent loggingEvent) {
loggingEvent.setProperty("xaName", getTransactionStatus(true) );
loggingEvent.setProperty("xaStatus", getTransactionStatus(false) );
return Filter.NEUTRAL;


To configure Log4J to use the new filter, edit the log4j.xml configuration file similar to the following (note use of %X{} in the conversion pattern):
   <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %X{xaStatus}- %m%n"/>
<filter class="com.skillcorp.transactionlogger.log4j.TransactionIndicatingFilter"/>
If your application uses log4j.properties rather than the xml configuration file, then another step is required. The log4j.properties format does not support configuration of filters. A workaround is to create a custom appender suited to the application, for instance, a custom ConsoleAppender:
public class TransactionIndicatingConsoleAppender extends org.apache.log4j.ConsoleAppender {
public TransactionIndicatingConsoleAppender()
addFilter(new TransactionIndicatingFilter());

Plugging into Java Logging

The logging framework built into Java also has a Filter layer that can be leveraged to insert our transaction decoration, but it does not have an analog to the MappedDiagnosticContext used with Log4J. To add our decoration in this case requires that we directly modify the application message in the logging record:

import static com.skillcorp.transactionlogger.TransactionIndicatingUtil.*;
public class TransactionIndicatingFilter implements Filter {
public boolean isLoggable(LogRecord record) {
record.setMessage(getTransactionStatus(isVerbose()) + record.getMessage());
return true;


Configuration is an additional wrinkle for the Java Logging filter. The transaction status can be indicated in either a terse or verbose format, selectable by the argument to getTransactionStatus(). In the Log4J filter above, the system simply adds both terse and verbose status fields to the MDC, and allows the appender / formatter to determine the correct log output. Since the MDC is not available in Java Logging, the filter must be configured to choose the correct output. The LogManager class exposes properties from the logging configuration file (default location: $JRE_HOME/lib/logging.properties)

    public TransactionIndicatingFilter() {
String $verbose = LogManager.getLogManager().getProperty(TransactionIndicatingFilter.class.getName() + ".verbose");
if ($verbose != null) {
verbose = Boolean.parseBoolean($verbose);
The logging.properties file should be configured as follows:

java.util.logging.ConsoleHandler.level = INFO
.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
.util.logging.ConsoleHandler.filter = com.skillcorp.transactionlogger.jdklog.TransactionIndicatingFilter

An Implementation

You can access a Maven-based project with the source code and test cases for demonstrating the decorated output for each logging framework. A binary of the logging solution is also available here


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}