The @Transactional Annotation

@Service
@Transactional
public class FooService {
    //...
}
  • the Propagation Type of the transaction
  • the Isolation Level of the transaction
  • a Timeout for the operation wrapped by the transaction
  • a readOnly flag – a hint for the persistence provider that the transaction should be read only
  • the Rollback rules for the transaction

Note that by default, rollback happens for runtime, unchecked exceptions only. The checked exception does not trigger a rollback of the transaction.

Potential Pitfalls

Transaction and Proxies

At a high level, Spring creates proxies for all the classes annotated with @Transactional, either on the class or on any of the methods. The proxy allows the framework to inject transactional logic before and after the running method, mainly for starting and committing the transaction.

This means that only external method calls that come in through the proxy will be intercepted. Any self-invocation calls will not start any transaction, even if the method has the @Transactional annotation.

Another caveat of using proxies is that only public methods should be annotated with @Transactional.

Changing the Isolation Level

Read-Only Transactions

This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.

The fact is that we can’t be sure that an insert or update won’t occur when the readOnly flag is set. This behavior is vendor dependent, whereas JPA is vendor agnostic.

It’s also important to understand that the readOnly flag is only relevant inside a transaction. If an operation occurs outside of a transactional context, the flag is simply ignored.

Transaction Rollback

@Transactional(rollbackFor = { SQLException.class })
public void createCourseDeclarativeWithCheckedException(Course course) throws SQLException {
    courseDao.create(course);
    throw new SQLException("Throwing exception for demoing rollback");
}