1 - @EnableTransactionManagement & Configure TransactionManager

  • @EnableTransactionManagement enables Spring’s annotation-driven transaction management capability (e.g. @Transactional)
  • see: TransactionManager

2 - Using @Transactional

public class UserService {

	@Transactional
    public Long registerUser(User user) {
    	// execute some SQL that e.g.
        // inserts the user into the db and retrieves the autogenerated id
        // userDao.save(user);
        return id;
    }
}

Armed with the knowledge from the JDBC transaction example, the @Transactional UserService code above translates (simplified) directly to this:

public class UserService {

    public Long registerUser(User user) {
        Connection connection = dataSource.getConnection();
        try (connection) {
            connection.setAutoCommit(false);

            // execute some SQL that e.g.
            // inserts the user into the db and retrieves the autogenerated id
            // userDao.save(user);

            connection.commit();
        } catch (SQLException e) {
            connection.rollback();
        }
    }
}

3 - @Transactional Attributes

Spring transaction provides support for following six attributes which determines the behavior of the transaction:

Attribute

Default

Description

@Transactional(transactionManager=?)

""

The name of TransactionManager bean that is going to drive the transactions

If the bean name of the TransactionManager that you want to wire in has the name transactionManager. If the TransactionManager bean that you want to wire in has any other name, you must use the transaction-manager attribute explicitly

@Transactional(propagation=?)

REQUIRED

The transaction propagation level

@Transactional(isolation=?)

DEFAULT

The transaction isolation level

@Transactional(timeout=?)

-1

The transaction timeout value (in seconds)

@Transactional(readOnly=?)

false

Is this transaction read-only?

@Transactional(rollbackFor=?)

{}

The Exception(s) as Classes that will trigger rollback

@Transactional(rollbackForClassName=?)

{}

The Exception(s) as Strings that will trigger rollback

@Transactional(noRollbackFor=?)

{}

The Exception(s) as Classes that will not trigger rollback

@Transactional(noRollbackForClassName=?)

{}

The Exception(s) as Strings that will not trigger rollback

4 - @Transactional Class vs Method Level

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // ...
    }
}

5 - @Transactional Under the Covers (Session)

In Spring, there is a one-to-one correspondence between the business transaction demarcated by @Transactional, and the hibernate Session.

That is, when a business transaction is begun by invoking a @Transactional method, the hibernate session is created (a TransactionManager may delay the actual creation until the session is first used). Once that method completes, the business transaction is committed or rolled back, which closes the hibernate session.

@Transactional can start new transaction or can join existing transactional context based its propagation attribute value.

In @Transactional context, getCurrentSession() method creates new Session object if it does not exist or returns Session which is attached to current transaction. openSession() method always creates new session. @Transactional helps you to extend scope of Session.

Session is open first time when getCurrentSession() is executed and it is closed when transaction ends and it is flushed before transaction commits.

In Spring, If we use getCurrentSession() in non-transactional context we get an exception

6 - @Transactional Under the Covers (CGlib & JDK Proxies)

Let’s see proxies in action in this picture:

As you can see from that diagram, the proxy has one job.

  • Opening and closing database connections/transactions (the proxy delegates that work to a TransactionManager)
  • And then delegating to the real UserService
  • And other beans, like your UserRestController will never know that they are talking to a proxy, and not the real thing