This tutorial shows an example on declarative transaction management in Spring. The declarative transaction management example uses two approaches – annotation based and XML based configurations. You can use as per your needs.

For introduction on Spring Transaction please go through Spring Transaction
Please follow the steps

Create a table in MySQL

CREATE TABLE `items` (
  `item_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `item_name` varchar(45) COLLATE latin1_general_ci NOT NULL,
  `item_desc` text COLLATE latin1_general_ci,
  `item_price` double unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`item_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

 

Dump some data

insert into `items`(`item_id`,`item_name`,`item_desc`,`item_price`)
values (1,'CD','CD is a compact disk',100),
(2,'DVD','DVD is larger than CD in size',150),
(3,'ABC','ABC test description',24),
(4,'XYZ','XYZ test description',25.32),
(5,'CD Player','CD player is used to play CD',30.02),
(6,'New Item1','New Item1 Desc',125);

 

Annotation based

Add <context:annotation-config/> to applicationContext.xml file to tell Spring to read @Transactional annotation
Add <tx:annotation-driven/> to applicationContext.xml file to wrap your code in transaction scope
Initialize the DataSourceTransactionManager bean in applicationContext.xml file

WEB-INF/jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cdcol
jdbc.username=root
jdbc.password=

 

WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:annotation-config></context:annotation-config><bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="jdbc.properties"></bean>
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverclassname="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean><bean id="itemDao" class="in.sblog.spring.dao.ItemDaoImpl"></bean><bean id="itemService" class="in.sblog.spring.service.ItemServiceImpl"></bean>
</beans>

 

I have put @Transactional annotation at the Service layer that knows about a unit of work because you may have several DAO classes, injected into a Service, that need to work together in a single transaction.

In the following Service class we have @Transactional annotation for declarative transaction. We can put put @Transactional annotation at class level or at method level. If we put @Transactional annotation at class level then it wraps all the method in a transaction scope. If we put @Transactional annotation at method level then it works with the particular method on which it is applied. We can put @Transactional annotation at class and at method level at the same time and in this case @Transactional annotation will be applied for all the methods with similar behaviour except the methods for which you have applied @Transactional annotation at method level will have different behaviour. @Transactional annotation has several properties such as readOnly, isolation, propagation, rollbackFor, noRollbackFor etc. These properties can be used to control the behaviour and communication with other transactions. We can use @Transactional(readOnly=true) for select queries and @Transactional for insert and update queries because by default readOnly=false. Another two important properties are rollbackFor and noRollbackFor – used for if a class throws exception the transaction will be rolled back for that exception class and rollback will not happen for that exception class respectively. I have written deleteItem() to throw an Exception so that I can show you how the data is rolled back on Exception.

Service class

import java.util.List;
public interface ItemService {
    List getItems();
    void addItem(Item item);
    void updateItem(Item item);
    void deleteItem(Item item) throws Exception;
}

 

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Transactional(propagation = Propagation.REQUIRED)
public class ItemServiceImpl implements ItemService {
    @Autowired
    ItemDao itemDao;
    @Transactional(readOnly = true)
    @Override
    public List getItems() {
        return itemDao.getItems();
    }
    @Override
    public void addItem(Item item) {
        itemDao.addItem(item);
    }
    @Override
    public void updateItem(Item item) {
        itemDao.updateItem(item);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteItem(Item item) throws Exception {
        itemDao.deleteItem(item);
    }
}

 

DAO Class

import java.util.List;
public interface ItemDao {
    List getItems();
    void addItem(Item item);
    void updateItem(Item item);
    void deleteItem(Item item) throws Exception;
}

 

I have thrown new Exception() from deleteItem() even after deletion of an item to show you that the data gets rolled back on Exception

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
public class ItemDaoImpl implements ItemDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Override
    public List getItems() {
        String sql = "SELECT * FROM items";
        List items = new ArrayList();
        items = jdbcTemplate.query(sql, new ItemRowMapper());
        return items;
    }
    @Override
    public void addItem(Item item) {
        String sql = "INSERT INTO items(item_id, item_name, item_desc, item_price) VALUES (?,?, ?, ?);";
        jdbcTemplate.update(
                sql,
                new Object[] { item.getItemId(), item.getItemName(),
                        item.getItemDesc(), item.getItemPrice() });
    }
    @Override
    public void updateItem(Item item) {
        String sql = "UPDATE items SET item_name=?, item_desc=?, item_price=? WHERE item_id=?;";
        jdbcTemplate.update(
                sql,
                new Object[] { item.getItemName(), item.getItemDesc(),
                        item.getItemPrice(), item.getItemId() });
    }
    @Override
    public void deleteItem(Item item) throws Exception {
        String sql = "DELETE FROM items WHERE item_id=?;";
        jdbcTemplate.update(sql, new Object[] { item.getItemId() });
        throw new Exception();
    }
}

 

Model class

public class Item {
    private Long itemId;
    private String itemName;
    private String itemDesc;
    private Double itemPrice;
    public Long getItemId() {
        return itemId;
    }
    public void setItemId(Long itemId) {
        this.itemId = itemId;
    }
    public String getItemName() {
        return itemName;
    }
    public void setItemName(String itemName) {
        this.itemName = itemName;
    }
    public String getItemDesc() {
        return itemDesc;
    }
    public void setItemDesc(String itemDesc) {
        this.itemDesc = itemDesc;
    }
    public Double getItemPrice() {
        return itemPrice;
    }
    public void setItemPrice(Double itemPrice) {
        this.itemPrice = itemPrice;
    }
}

 

JDBC utility classes

import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
public class ItemExtracter implements ResultSetExtractor {
    @Override
    public Item extractData(ResultSet resultSet) throws SQLException,
            DataAccessException {
        Item item = new Item();
        item.setItemId(resultSet.getLong(1));
        item.setItemName(resultSet.getString(2));
        item.setItemDesc(resultSet.getString(3));
        item.setItemPrice(resultSet.getDouble(4));
        return item;
    }
}

 

import java.sql.ResultSet;
import java.sql.SQLException;
import in.sblog.spring.model.Item;
import org.springframework.jdbc.core.RowMapper;
public class ItemRowMapper implements RowMapper {
    @Override
    public Item mapRow(ResultSet resultSet, int rowNum) throws SQLException {
        ItemExtracter itemExtracter = new ItemExtracter();
        return itemExtracter.extractData(resultSet);
    }
}

 

Test the Spring Transaction

import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpringTransaction {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        ItemService itemService = (ItemService) applicationContext
                .getBean("itemService");
        try {
            Item delItem = new Item();
            delItem.setItemId(6l);
            itemService.deleteItem(delItem);
            System.out.println("Item Successfully Deleted.");
        } catch (Exception ex) {
            System.out.println("Item was not deleted.");
            System.out.println("Transaction rolled back due to Exception.");
        }
        System.out.println();
        System.out.println("======================================");
        System.out.println("List of Items");
        System.out.println("======================================");
        List items = itemService.getItems();
        for (Item item : items) {
            System.out.println("Item Id: " + item.getItemId());
            System.out.println("Item Name: " + item.getItemName());
            System.out.println("Item Desc: " + item.getItemDesc());
            System.out.println("Item Price: " + item.getItemPrice());
        }
    }
}

 

XML configuration based

We have to change only in applicationContext.xml and ItemServiceImpl.java

Initialize the DataSourceTransactionManager bean in applicationContext.xml file as shown for the Annotation based configuration.
Add <tx:advice /> to applicationContext.xml file to configure the transaction advice. Vaarious transaction properties can be configured for different methods. So now instead of @Transactional(readOnly = true) we will write <tx:method name=”get*” read-only=”true” />. For rollback on Exception we write <tx:method name=”delete*” rollback-for=”java.lang.Exception” propagation=”REQUIRED” />
Add <aop:config/> to applicationContext.xml file to apply the transaction advice using Spring AOP configuration

WEB-INF/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <context:annotation-config></context:annotation-config><bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="jdbc.properties"></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"></tx:method>
            <tx:method name="delete*" rollback-for="java.lang.Exception" propagation="REQUIRED"></tx:method>
            <tx:method name="*"></tx:method>
        </tx:attributes>
    </tx:advice><aop:config><aop:pointcut id="itemServiceTxPointcut" expression="execution(* in.sblog.spring.service.ItemService.*(..))"></aop:pointcut><aop:advisor advice-ref="txAdvice" pointcut-ref="itemServiceTxPointcut"></aop:advisor>
    </aop:config><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverclassname="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean><bean id="itemDao" class="in.sblog.spring.dao.ItemDaoImpl"></bean><bean id="itemService" class="in.sblog.spring.service.ItemServiceImpl"></bean>
</beans>

 

Service implementation Class

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class ItemServiceImpl implements ItemService {
    @Autowired
    ItemDao itemDao;
    @Override
    public List getItems() {
        return itemDao.getItems();
    }
    @Override
    public void addItem(Item item) {
        itemDao.addItem(item);
    }
    @Override
    public void updateItem(Item item) {
        itemDao.updateItem(item);
    }
    @Override
    public void deleteItem(Item item) throws Exception {
        itemDao.deleteItem(item);
    }
}

 

If we run the TestSpringTransaction.java we will get the same result for Annotation and XML based configurations.

Output

Item was not deleted.
Transaction rolled back due to Exception.
======================================
List of Items
======================================
Item Id: 1
Item Name: CD
Item Desc: CD is a compact disk
Item Price: 100.0
Item Id: 2
Item Name: DVD
Item Desc: DVD is larger than CD in size
Item Price: 150.0
Item Id: 3
Item Name: ABC
Item Desc: ABC test description
Item Price: 24.0
Item Id: 4
Item Name: XYZ
Item Desc: XYZ test description
Item Price: 25.32
Item Id: 5
Item Name: CD Player
Item Desc: CD player is used to play CD
Item Price: 30.02
Item Id: 6
Item Name: New Item1
Item Desc: New Item1 Desc
Item Price: 125.0

 

Thanks for your reading. Please leave a comment if you any query.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit

0 thoughts on “Declarative Transaction Management Example in Spring

Leave a Reply

Your email address will not be published. Required fields are marked *