Tom has posted 1 posts at DZone. View Full User Profile

Monitoring Declarative Transactions in Spring

12.01.2008
| 43620 views |
  • submit to reddit

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:

    @Transactional    
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

Legacy
Published at DZone with permission of its author, Tom Cellucci.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Yaozong Zhu replied on Mon, 2008/12/01 - 4:49am

This is quite a good idea indeed. I usually assume Spring transaction working for my apps without verifying it properly. Another idea comes up with from my little brain is to use Spring AOP, and all of your work could be done just in Spring configuration file instead.

Hoikin Wong replied on Mon, 2008/12/01 - 9:55am

Why not just enable spring's logger to monitor the transaction ?

Tom Cellucci replied on Mon, 2008/12/01 - 10:08am in response to: Yaozong Zhu

Using Spring AOP was an option that I considered as a solution, but it had a couple of negatives that swayed me towards the logging.  The first problem is that Spring AOP is just as 'magical' as the declarative transaction management itself, and therefore as prone to misconfiguration.  The second was that it's a little more intrusive to modify the spring configuration for an app after it's deployed; the typical WAR would have to be opened, modified and redeployed with the changes.  Certainly a viable solution though, not a bad idea at all if AOP's in your toolkit and you're implementing prior to deployment. 

-Tom

Tom Cellucci replied on Mon, 2008/12/01 - 10:18am in response to: Hoikin Wong

You certainly can turn on Spring's logging and get some output that indicates where the transactions start and stop.  The problem is that this output can end up far, far away from the logging output of code that is of interest.  In my experience a web application will open a transaction via filter when the request is recieved, and commit/rollback when it's done.  For significant applications, there can be many layers of logging between those points that obscure the transaction origin.  Compounding the problem is multi-threaded output, where the 'begin' or 'commit' logging that's immediately visible may not be from the thread executing the code of interest.  The solution proposed here decorates the logging statements your application already emits, so its transactional status is immediately obvious.

Yaozong Zhu replied on Mon, 2008/12/01 - 12:33pm in response to: Tom Cellucci

I can understand your point. It's like introducing a mechanism to monitor the same mechanism. It's just a quick and one-place-setting way to verify if transaction is working or not.

 

Our projects use JMX to adapt logging on the fry, which could be an backup solution for existing jmx-enabled system to turn on or off loggers retrieving relevant information with a plenty of irrevant one as you mentioned.

Paul Hixson replied on Mon, 2008/12/01 - 1:48pm

Nice article.  Reminds me of the time I spent a couple of days figuring out the a client needed record versioning in Hibernate.  Spring is so nice and quiet that it is hard to tell when something like TM is misconfigured. 

I like the logging solution personally, since, once you find something like this, it's always a prime suspect in future problems.  Logging quickly let's you prove the solution is still working.

Also, you're a better man than I am for plumbing the depths of Log4j **shudders**.

Rick Hightower replied on Mon, 2008/12/01 - 10:28pm

Nice. Good stuff! Thanks Tom.

Paul Grove replied on Wed, 2008/12/03 - 3:32am

Have you considered doing an example for LogBack? Log4j is no longer under active development and it seems to me SL4J with LogBack is starting to gain traction and will be the next evolution in Java logging. No more class loader issues of JCL!

Nice example thou cheers 

Tom Cellucci replied on Wed, 2008/12/03 - 10:43am in response to: Paul Grove

I worked up a quick example that uses Logback and SLF4J; it's present in the attachments.

Jan Novotný replied on Tue, 2008/12/09 - 12:34am

We have come to the same solution. I have published article (http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/) on the same topic several months ago and ended up with the similar recommendation as you. The difference is, that I examine standard logging output of transaction advice (as well as other possible advices we want to check) instead of calling API on advised objects as you do. This way I am able to easily check even other Aspects than just Spring transaction Aspect, but on the other hand I am somewhat depending on advice internals - such as logging messages. I am trying to get over that issue with encapsulation of log messages checker. If you want to know details of my solutions, please go check it there: http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/ (it's in English).

Carla Brian replied on Sun, 2012/07/29 - 5:28am

The ideas here are nice. At least I have learned new this day. This could really be helpful in the future. Good job on this. - Instant Tax Solutions Ratings

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.