Spring - Declarative Transaction Management with @Transactional Annotation

[Updated: Sep 12, 2017, Created: Sep 6, 2017]

@Transactional provides annotation-based declarative transaction support which is similar to EJB container-managed transaction. With this annotation, we can specify transaction behavior to individual methods without coupling business logic with transaction code.

This example demonstrates the use of @Transactional annotation with it's default settings.


We are going to reuse our previous example. We will create a service layer where we will be using @Transactional annotation.

Service Layer

We can place the @Transactional annotation on an interface definition, a method of an interface, a class definition, or a public method of a class. When placed on the class/interface level, all methods within it will become transactional.

package com.logicbig.example;

import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface OrderService {

  void persistOrders(List<OrderItem> orderItems);

  List<OrderItem> getAllOrders();
public class OrderServiceImpl implements OrderService {

  private Dao<OrderItem> dao;

  public void persistOrders(List<OrderItem> orderItems) {
      for (OrderItem orderItem : orderItems) {
          long id = dao.save(orderItem);
          System.out.println("id generated: " + id);

  public List<OrderItem> getAllOrders() {
      return dao.loadAll();

Using the service

public class OrderItemClientBean {
  private OrderService orderService;

  public void persistOrderItems() {
      List<OrderItem> orders = Arrays.asList(
              new OrderItem("BWell Ethernet Cable", 5),
              new OrderItem("EDrive SSD", 2000)
      try {
      } catch (Exception e) {
      List<OrderItem> allOrders = orderService.getAllOrders();
      System.out.println("loaded orders: " + allOrders);

      System.out.println("-- second attempt --");
      List<OrderItem> orders2 = Arrays.asList(
              new OrderItem("BWell Ethernet Cable", 5),
              new OrderItem("EDrive SSD", 20)
      try {
      } catch (Exception e) {
      List<OrderItem> allOrders2 = orderService.getAllOrders();
      System.out.println("loaded orders: " + allOrders2);

  private static void logException(Exception e) {
      System.out.println("-- exception --");
      System.err.println("Exception: "+e.getClass().getName());
      System.err.println("Message: "+ e.getMessage());

In above example, we are performing two transactions. The first transaction will fail and will be rolled back, that's because we are inserting a value for OrderItem#qty which is out of the integer range defined in the corresponding table column. This is to demonstrate that the service method annotated with @Transactional is providing the method level transaction as expected. Without it persisting process will not be aromatic for the list of provided orders. The second transaction should be committed successfully.

Java Config

public class AppConfig {

  public DataSource h2DataSource() {
      return new EmbeddedDatabaseBuilder()

  public PlatformTransactionManager transactionManager() {
      DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
      return transactionManager;

In above configuration, EnableTransactionManagement annotation enables Spring's annotation-driven transaction management.

Main class

public class ExampleMain {
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(AppConfig.class);
      OrderItemClientBean orderItemClientBean = context.getBean(OrderItemClientBean.class);


id generated: 1
-- exception --
Exception: org.springframework.dao.DataIntegrityViolationException
Message: PreparedStatementCallback; SQL []; Check constraint violation: "((QTY > 0)
AND (QTY <= 100))"; SQL statement:
insert into ORDER_ITEM (ITEM, QTY) values (?, ?) [23513-196]; nested exception is org.h2.jdbc.JdbcSQLException: Check constraint violation: "((QTY > 0)
AND (QTY <= 100))"; SQL statement:
insert into ORDER_ITEM (ITEM, QTY) values (?, ?) [23513-196]
loaded orders: []
-- second attempt --
id generated: 3
id generated: 4
loaded orders: [OrderItem{id=3, item='BWell Ethernet Cable', qty=5}, OrderItem{id=4, item='EDrive SSD', qty=20}]

Using @javax.transaction.Transactional

Spring provides the exact same functionality for the standard javax.transaction.Transactional annotation without any extra configuration. We just need to add following maven dependency to use it:


Example Project

Dependencies and Technologies Used :

  • spring-context 4.3.10.RELEASE: Spring Context.
  • spring-jdbc 4.3.10.RELEASE: Spring JDBC.
  • h2 1.4.196: H2 Database Engine.
  • JDK 1.8
  • Maven 3.3.9

@Transactional Example Select All Download
  • transactional-annotation-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources

See Also