Spring Transaction with @Transactional explained

The most easy way to Spring Transaction is to use @Transactional. The following is basic step to use it.

Required spring component

spring-context.jar, spring-tx.jar, spring-jdbc.jar and additional dependencies

Spring context

  • <tx:annotation-driven> must be declared to enable @Transactional
  • TransactionManager must be declared. If the id is not “transactionManager“, it must be set with <tx:annotation-driven>’s transaction-manager attribute
  • Sample context.xml


  • TransactionManager’s id is “testTransactionManager”
  • “testTransactionManager” is mapped with “testDataSource”
  • Spring transaction is enabled with <tx:annotation-driven>

Bean with @Transactional

  • @Transactional can be declared at interface, class or method level
  • If @Transactional is declared at a method, it must be public
  • Sample dao
package test.dao;

import javax.sql.DataSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

public class TestDao {
	private JdbcTemplate jdbcTemplate;

	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);

	public void insertData(String col1, String col2) {
		this.jdbcTemplate.update("INSERT INTO TRANSACTION_TEST(COL1, COL2) VALUES(?, ?)", col1, col2);

Accessing transactional bean

  • Spring Transaction uses AOP to implement transaction
  • Bean with @Transactional is wrapped with a AOP Proxy
  • Proxy object is generated with JDK dynamic proxy or CGLIB-based proxy. If the bean is interface-based, JDK proxy is used. But if the bean is without interface or CGLIB is foreced, CGLIB is used. (CGLIB is forced if <tx:annotation-driven proxy-target-class=”true” /> is set)
  • Accessing transactional bean must be through Spring context. If accessed directly, the reference is not proxy but dao itself. Therefore transaction is not applied
  • Sample code
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.dao.TestDao;
import test.dao.TestMultiDao;

public class TransactionTest {

	public static void main(String[] args) {
		TransactionTest transactionTest = new TransactionTest();
		ApplicationContext context = transactionTest.getSpringContext();
		TestDao testDao = context.getBean(TestDao.class);
		testDao.insertData("1", "111");
		testDao.insertData("2", "222");

    private ApplicationContext getSpringContext(){
        String contextFileName = "context.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {contextFileName});
        return context;

Internal working of Spring Transaction

Within transactional method, underlying jdbc connection is set as manual commit and transaction is committed before the method ends. To prove it, check the following log. (When running above code)

DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Creating new transaction with name [test.dao.TestDao.insertData]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ”
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Acquired Connection […] for JDBC transaction
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Switching JDBC Connection […] to manual commit
DEBUG: org.springframework.jdbc.core.JdbcTemplate – Executing prepared SQL update
DEBUG: org.springframework.jdbc.core.JdbcTemplate – Executing prepared SQL statement [INSERT INTO TRANSACTION_TEST(COL1, COL2) VALUES(?, ?)]
DEBUG: org.springframework.jdbc.core.JdbcTemplate – SQL update affected 1 rows
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Initiating transaction commit
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Committing JDBC transaction on Connection […]
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager – Releasing JDBC Connection […] after transaction
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils – Returning JDBC Connection to DataSource

But if @Transactional is not used, no message about transaction is shown

Worst practice

If transactional bean or method is accessed directly, no transaction is applied. The following is the example

public class TestDao {

	public void insertData(String col1, String col2) {
		this.jdbcTemplate.update("INSERT INTO TRANSACTION_TEST(COL1, COL2) VALUES(?, ?)", col1, col2);

	public void insertDataWithoutTransaction(String col1, String col2) {
		insertData(col1, col2);

Calling insertDataWithoutTransaction() is without transaction although it calls transactional insertData() inside, because insertData() is accessed through this (TestDao object), not through proxy


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.