About Baskaran Chinnusamy

Baskaran Chinnusamy is a software engineer has developed frameworks for companies. He also involved in different application developments and performance tunings. Currently he leads project development and designing applications

Java Nested Transaction using ThreadLocal in POJO

Mostly nested transaction was implemented using EJB , now we try to implement the nested transaction on POJO. Here we have used the feature of ThreadLocal.

Understanding Nested Transaction

Transactions can be nested one inside another.  So the inner transaction or outer transaction can be rollback or commit without affecting the other transaction.

When a new transaction is created then it comes under the outer transaction. Once the inner transaction is completed in either case commit or rollback, the outer transaction can perform either commit or rollback without related to inner transaction. First close the innermost transaction and move on to the outer.

Image1

Implementing using Simple POJO

Creating interface as below:

importjava.sql.Connection;

publicinterfaceTransactionManager {

	Connection getConnection();
	voidbeginTransaction();
	void commit();
	void rollback();
}

Creating Transaction Manager class as below:

importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.SQLException;
importjava.util.Stack;

publicclassTransactionManagerStackImplimplementsTransactionManager {
	
	private Stack<Connection>connections = new Stack<Connection>();

	@Override
	public Connection getConnection() {

		if (connections.isEmpty()) {
			this.addConn();
		}

		returnconnections.peek();
	}

	@Override
	publicvoidbeginTransaction() {
		this.addConn();
	}

	@Override
	publicvoid commit() {
		try {
			if (connections.peek() != null&& !connections.peek().isClosed()) {
				System.out.println(connections.peek().toString() +"--Commit---");
				connections.peek().commit();
				connections.pop().close();
			}

		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	@Override
	publicvoid rollback() {
		try {

			if (connections.peek() != null&& !connections.peek().isClosed()) {
				System.out.println(connections.peek().toString() +"--Rollback---");
				connections.peek().rollback();
				connections.pop().close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	privatevoidaddConn() {
		try {
			Connection con = this.getMysqlConnection();
			con.setAutoCommit(false);
			connections.push(con);
			System.out.println(con.toString() +"--Conection---");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
	}

	private Connection getMysqlConnection() {
		returngetConnection("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/testdb", "test", "test12345");
	}

	private Connection getConnection(String driver, String connection,
			String user, String password) {

		try {
			Class.forName(driver);
			returnDriverManager.getConnection(connection, user, password);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		returnnull;

	}
}

Here we have created a Stack:

private Stack<Connection> connections = new Stack<Connection>();

As the transactions are created as LIFO (Stack) we have used Stack from Java API to maintain connections for each transaction:

public void beginTransaction()

Begin transaction to begin a new transaction and add the connection to the Stack. AutoCommit has been set to false:

public Connection getConnection()

Get Connection for the current transactions. If not exist it will create and add to stack:

public void commit()

Commit the current transaction and close the connection, also removed from stack:

public void rollback()

Rollback the current transaction and close the connection, also removed from stack.

The above class TransactionManagerStackImpl   will create nested transaction for single thread.

Nested Transaction for Multithreads

In case of multithreaded application, each thread has separate transaction and nested transaction.

We came up using ThreadLocal to manage the stack of connections.

importjava.sql.Connection;

publicclassTransactionManagerThreadLocalimplementsTransactionManager {
	
	privatestaticfinalThreadLocal<TransactionManager>tranManager = newThreadLocal<TransactionManager>() {
		
	protectedTransactionManagerinitialValue() {
		System.out.println(this.toString() + "--Thread Local Initialize--");
	returnnewTransactionManagerStackImpl();
	    }
	  };

	@Override
	publicvoidbeginTransaction() {
		tranManager.get().beginTransaction();
	}

	@Override
	publicvoid commit() {
		tranManager.get().commit();
	}

	@Override
	publicvoid rollback() {
		tranManager.get().rollback();
	}

	@Override
	public Connection getConnection() {
		returntranManager.get().getConnection();
	}
}

Here we initialize TransactionManagerStackImpl to create nested transaction inside the thread.

Testing

For testing this above, commit inner transaction and rollback outer transaction.

importjava.sql.Connection;

publicclassNestedMainimplements Runnable {
	
	privateintv = 0;
	private String name;
	
	NestedMain(int v, String name) {
		this.v = v;
		this.name = name;
	}

	publicstaticvoid main(String[] args) throws Exception{
		
		for (inti = 0; i< 3; i++) {
			NestedMain main = newNestedMain(i * 10, "Ravi" + i);
			new Thread(main).start();
		}
	}

	@Override
	publicvoid run() {
		
		try {
			TransactionManagerThreadLocal local = newTransactionManagerThreadLocal();
			
			// Transaction 1 ( outer )
			local.beginTransaction();
			Connection con = local.getConnection();
			String sql = "INSERT INTO test_tran (emp_id, name) VALUES ('1"+v+"', '"+ name+v+"')";
			this.insert(con, sql);
	
				// Transaction 2 ( Inner )
				local.beginTransaction();
				con = local.getConnection();
				sql = "INSERT INTO test_tran (emp_id, name) VALUES ('2"+v+"', '"+ name+v+"')";
				this.insert(con, sql);
				local.commit(); // Committing 2

			local.rollback(); // Rollback 1 Outer

		} catch (Exception e) {
			e.printStackTrace();
		}

Result

com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.mysql.jdbc.JDBC4Connection@10dd1f7--Conection---
com.mysql.jdbc.JDBC4Connection@1813fac--Conection---
com.mysql.jdbc.JDBC4Connection@136228--Conection---
com.mysql.jdbc.JDBC4Connection@1855af5--Conection---
com.mysql.jdbc.JDBC4Connection@e39a3e--Conection---
com.mysql.jdbc.JDBC4Connection@1855af5--Commit---
com.mysql.jdbc.JDBC4Connection@e39a3e--Commit---
com.mysql.jdbc.JDBC4Connection@9fbe93--Conection---
com.mysql.jdbc.JDBC4Connection@9fbe93--Commit---
com.mysql.jdbc.JDBC4Connection@10dd1f7--Rollback---
com.mysql.jdbc.JDBC4Connection@1813fac--Rollback---
com.mysql.jdbc.JDBC4Connection@136228--Rollback---
nameemp_id
Ravi220220
Ravi0020
Ravi110210

When rollback inner transaction and commit outer transaction:

com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.ttit.TransactionManagerThreadLocal$1@1270b73--Thread Local Initialize--
com.mysql.jdbc.JDBC4Connection@9f2a0b--Conection---
com.mysql.jdbc.JDBC4Connection@136228--Conection---
com.mysql.jdbc.JDBC4Connection@1c672d0--Conection---
com.mysql.jdbc.JDBC4Connection@9fbe93--Conection---
com.mysql.jdbc.JDBC4Connection@1858610--Conection---
com.mysql.jdbc.JDBC4Connection@9fbe93--Rollback---
com.mysql.jdbc.JDBC4Connection@1858610--Rollback---
com.mysql.jdbc.JDBC4Connection@1a5ab41--Conection---
com.mysql.jdbc.JDBC4Connection@1a5ab41--Rollback---
com.mysql.jdbc.JDBC4Connection@9f2a0b--Commit---
com.mysql.jdbc.JDBC4Connection@136228--Commit---
com.mysql.jdbc.JDBC4Connection@1c672d0--Commit---
nameemp_id
Ravi0010
Ravi220120
Ravi110110

Resource:

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


five − = 0



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close