Thread scope and ThreadLocal

Introduction

When we implement a java servlet web application we face the problem of choosing in which scope to put information in, depending on the needs. In the normal scenarios we have to cope essentially with Context (i.e. ServletContext), Session and Request scopes.
A slightly different requirement comes out when one wants to store some object or information in the current thread, so that it would be isolated from other threads. Someone might say that the ServletRequest object would fit this requirement, because each request runs in a separate thread and one could simply store the information he wants as a request attribute, but in a classical multilayer application the request object won’t be available in the business logic layer nor in the data access layer.
A java class called ThreadLocal comes in handy in these situations. In this brief article we will describe the very basics of the ThreadLocal’s usage.

A Sample Scenario

As a scenario that could describe well why there is the need of storing objects in a Thread scope we will describe the implementation of a tipical Data Access Object layer keeping it as simple as possible. We have picked this example only because it explains well the point, but please keep in mind that there are many out the of the box solutions for DAO’s pattern, both in the form of pure JDBC (Spring’s JdbcTemplate) and more advanced ORM frameworks and there is no point to, as they say, ‘reinvent the weel’.
A tipical issue with implementing a DAO layer is to emcompass two or more database operations in a single transaction. Here we are talking about operations that change the data state, such as inserts, deletes and updates. To deal with this we can create the JDBC connection set the autocommit property to false and pass it as a parameter to each of the DAO method calls involved, then after having called all the methods in the transaction execute commit (or rollback in case of errors) on the connection object.
This approach though couples the DAO methods signature with the JDBC connection. It would be nice if we could get a ‘cleaner’ version of our DAO interfaces, making it unaware of the connection. A way to do this would be to implement some sort of transaction manager class with static methods whith the responsibility of creating the connection (or getting it from a connection pool), storing it in the current thread, giving it to the DAO obect caller and handle the transaction boundaries between the DAO method calls. The part of storing the connection in the current thread can be made by using a Java class called ThreadLocal, in the following paragraph we show a simple example on how this can be done.

Concrete Example

In the following example we use very simple classes just to explain how the all ThreadLocal thing works. First of all we implement a minimal transfer object:

public class SampleTranferObject {

	private String sampleField;

	public String getSampleField() {
		return sampleField;
	}

	public void setSampleField(String sampleField) {
		this.sampleField = sampleField;
	}

}

A simple DAO interface and implementation:

 import java.util.List;

 public interface SampleDao
 {

  public void addSampleField(SampleTranferObject tranferObject);

 }

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class SampleDaoImpl implements SampleDao

{

	public void addSampleField(SampleTranferObject tranferObject) {
		Connection con = null;
		Statement statement = null;

		String sql = "insert into SampleTable values("
				+ tranferObject.getSampleField() + ")";
		try {
			con = SampleTransactionManager.getConnection();
			statement = dbConnection.prepareStatement(sql);
			statement.executeUpdate(sql);
		}
		catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

		}
	}
}

And finally our transaction manager:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class SampleTransactionManager

{
	Connection connection = null;
	static ThreadLocal local = new ThreadLocal();

	public static void startTransaction() throws SQLException

	{
		Connection con = DriverManager.
getConnection("jdbc:mysql://localhost:3306/mysql");	
		con.setAutoCommit(false);
		local.set(con);			
	}

	public static Connection getConnection() throws SQLException

	{
		Connection con = local.get();
		return con;
	}

	public static void commit()
	{
		Connection con = local.get();
		if(con != null){
			try {
				con.commit();
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	}

	public static void rollback()
	{
		Connection con = local.get();
		if(con != null){
			try {
				con.rollback();
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	}

}

The class SampleTransactionManager has a startTransaction method that creates a new connection, set the autocommit to false so that each database operation is not commited until the commit method on the connection is explicitly called, and finally stores the connection in a static ThreadLocal variable. The magic behind ThreadLocal class makes the connection beeing actually stored in the current Thread. This method will be called outside of the DAO object method calls to mark the transaction’s start.
The method getConnection retrieves the connection from the ThreadLocal variable and returns it to the caller, i.e. the DAO object.

Let’s put this all together in the following code:

    SampleDao employeeDao = new SampleDaoImpl();
    SampleTranferObject tranferObject1 = new SampleTranferObject();
    SampleTranferObject tranferObject2 = new SampleTranferObject();
    tranferObject1.setSampleField("sampleValue1");
    tranferObject2.setSampleField("sampleValue2");
    try {
	SampleTransactionManager.startTransaction();	
	employeeDao.addSampleField(tranferObject1);
	employeeDao.addSampleField(tranferObject2);
	SampleTransactionManager.commit();

    } catch (SQLException e) {
	SampleTransactionManager.rollback();
    }

The employeeDao instance is used to add two values to a database table by tranferObject1 and tranferObject2 variables. As we see the SampleTransactionManager is used to start the transaction and to commit or rollback. The addSampleField method does not need the connection to be passed in as a parameter since, as we see in the DAO implementation it is retrieved internally using the static SampleDao’s getConnection method.

Conclusions

We have seen how the use of ThreadLocal allows us to access the current thread context and store objects in it. In this particular example we managed to keep the DAO methods signature ‘cleaner’ and independent of the connection in a tipical transactional scenario (what shown here could be improved to get the DAO internally free of JDBC boilerplate code and focused mainly on SQL , like Spring does with JdbcTemplate).

Thread scope and ThreadLocal last modified: 2015-04-26T21:24:14+00:00 by Mario Casari

Leave a Reply

Your email address will not be published. Required fields are marked *