Thursday, May 21, 2020

Spring Transaction Management Example - @Transactional Annotation and JDBC

In the post Transaction Management in Spring we have already seen the details about transaction management in Spring. In this post, building on that knowledge we’ll see an example of transaction management in Spring with JDBC. This Spring transaction management example uses declarative transaction using @Transactional annotation.

Technologies used

  • Spring 5.0.4
  • Apache DBCP2
  • MYSQL 5.1.39
  • Java 8
  • Apache Maven 3.3.3

In the transaction management example, Apache DBCP is used for providing pooled JDBC datasource and MYSQL is used as the back end.


Maven dependencies

If you are using Maven then you can provide dependencies in your pom.xml.

Refer Creating a Maven Project in Eclipse to see how to set up Maven project.

With all the required dependencies your pom.xml should look something like this -

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.netjs.spring</groupId>
  <artifactId>SpringProj</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  
  <name>SpringProj</name>
  <url>http://maven.apache.org</url>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>5.0.4.RELEASE</spring.version>
  </properties>

  <dependencies>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
     <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    
    <!-- Spring JDBC Support -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
   <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.39</version>
    </dependency>
    
    <!--  Apache DBCP connection pool -->
    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-dbcp2</artifactId>
       <version>2.1</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Alternatively you can download the jars and add them to the class path.

Spring declarative transaction management JDBC example

Now the basic project structure is in place and we should create DB tables and classes for the project. In this Spring transaction management example we’ll have two DB tables employee and address and when employee record and employee’s address records are inserted with in a transaction, either both of them should be inserted correctly or none of them.

Database tables

Here is the table structure for both employee and address tables.

CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 
CREATE TABLE `address` (
  `id` int(11) NOT NULL,
  `address` varchar(20) DEFAULT NULL,
  `city` varchar(20) DEFAULT NULL,
  KEY `id_idx` (`id`),
  CONSTRAINT `id` FOREIGN KEY (`id`) REFERENCES `employee` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
)

JDBC Data Source

For this example Apache DBCP is used and DB properties are read from a properties file.

Bean definition for data source is as follows-
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value = "${db.driverClassName}" />
    <property name="url" value = "${db.url}" />
    <property name="username" value = "${db.username}" />
    <property name="password" value = "${db.password}" />
    <property name="initialSize" value = "${pool.initialSize}" />
</bean>

db.properties file

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=
db.password=
pool.initialSize=5

Spring transaction management example – Java classes

The flow in the example is; first service bean is called which in turn calls a DAO class and from there the DB call.

The classes needed for this flow are as follows-

  1. Employee and Address Beans
  2. Service interface and Service implementation class
  3. DAO interface and DAO implementation class.
With all these classes project structure will look like as follows-
spring transaction management example

Employee.java

public class Employee {
 private int empId;
 private String empName;
 private int age;
 private Address address;
 public int getEmpId() {
  return empId;
 }
 public void setEmpId(int empId) {
  this.empId = empId;
 }
 public String getEmpName() {
  return empName;
 }
 public void setEmpName(String empName) {
  this.empName = empName;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public Address getAddress() {
  return address;
 }
 public void setAddress(Address address) {
  this.address = address;
 }
}

Address.java

public class Address {
 private int id;
 private String addrLine; 
 private String city;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getAddrLine() {
  return addrLine;
 }
 public void setAddrLine(String addrLine) {
  this.addrLine = addrLine;
 }
 public String getCity() {
  return city;
 }
 public void setCity(String city) {
  this.city = city;
 } 
}

EmployeeDAO.java interface

public interface EmployeeDAO {
  public Employee findEmployee(int empId);
  public void insertEmployee(Employee emp);
}

EmployeeDAOImpl.java

@Repository
public class EmployeeDAOImpl implements EmployeeDAO {
  @Autowired
  private JdbcTemplate jdbcTemplate; 
  @Override
  public Employee findEmployee(int empId) {
    final String SELECT_BY_ID_QUERY = "select emp.id, name, age, address, city from employee emp, address adr "
        + "where emp.id = adr.id and emp.id = ?";
    return this.jdbcTemplate.queryForObject(SELECT_BY_ID_QUERY, 
          new EmployeeMapper(), 
          empId);
  }
    
  private static final class EmployeeMapper implements RowMapper<Employee> {
    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
      Employee emp = new Employee();
      Address addr = new Address();
      emp.setEmpId(rs.getInt("id"));
      emp.setEmpName(rs.getString("name"));
      emp.setAge(rs.getInt("age"));
      addr.setAddrLine("address");
      addr.setCity("city");
      emp.setAddress(addr);
      return emp;
    }
  }
    
  @Override
  public void insertEmployee(Employee emp) {
    final String INSERT_EMP_QUERY = "insert into employee (id, name, age) values (?, ?, ?)";
    final String INSERT_ADDR_QUERY = "insert into address (id, address, city) values (?, ?, ?)";

    jdbcTemplate.update(INSERT_EMP_QUERY, emp.getEmpId(), emp.getEmpName(), emp.getAge());
    System.out.println("Employee record inserted");
    jdbcTemplate.update(INSERT_ADDR_QUERY, emp.getEmpId(), emp.getAddress().getAddrLine(), emp.getAddress().getCity());
    System.out.println("Employee address record inserted");
  }
}

In the EmployeeDAOImpl class there are two methods one for inserting records and one for finding an employee. Note that Spring jdbcTemplate is used here for data access. In the insertEmployee() method there are two insert queries one for inserting employee record and another one for address of the employee. If this method is running in a transaction and some thing goes wrong while inserting address record, employee record which is already inserted should also roll back.

EmployeeService.java interface

public interface EmployeeService {
  public Employee getEmployee(int empId);
  public void addEmployee(Employee emp);
}

EmployeeServiceImpl.java

import org.netjs.dao.EmployeeDAO;
import org.netjs.model.Employee;
import org.netjs.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
public class EmployeeServiceImpl implements EmployeeService {
 @Autowired
 private EmployeeDAO empDAO;

 @Override
 public Employee getEmployee(int empId) {
  return empDAO.findEmployee(empId);
 }

 @Override
 @Transactional(propagation=Propagation.REQUIRED,readOnly=false)
 public void addEmployee(Employee emp) {
  empDAO.insertEmployee(emp);
 }
}

As far as the Spring transaction management example goes this is the class where all the transaction related activities happen. As you can see @Transactional annotation is used for declarative transaction. For the whole class transaction management setting is to support transaction if exists and read only optimizations should be applied. In the method addEmployee() transaction settings are overridden and for this method transaction is required and read only is false. Default settings are used for roll back of the transaction where the roll back happens if RunTime exception is thrown.

Also notice the convenience of using Spring declarative transaction. You don’t need to write with in the code where transaction starts, where it ends and when to roll back, you just have to declare the transaction settings for the method and the Spring transaction management will take care of all the boiler plate code for transaction.

XML configuration for the Spring transaction management example

Here is the XML configuration for the example (appContext.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:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd
  http://www.springframework.org/schema/tx 
  http://www.springframework.org/schema/tx/spring-tx.xsd">
    
  <context:component-scan base-package="org.netjs.serviceImpl, org.netjs.DAOImpl" />
  <!--  For reading properties files --> 
  <context:property-placeholder location="classpath:config/db.properties" />
    
  <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value = "${db.driverClassName}" />
    <property name="url" value = "${db.url}" />
    <property name="username" value = "${db.username}" />
    <property name="password" value = "${db.password}" />
    <property name="initialSize" value = "${pool.initialSize}" />
  </bean>
  <!--  Transaction Manager --> 
  <bean id="txManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>
  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    <property name="dataSource" ref="dataSource"></property>  
  </bean>  
  <tx:annotation-driven proxy-target-class="true" transaction-manager="txManager" />
</beans>

In the XML, Spring transaction management related configuration is listed below-

  1. You need to define the correct Transaction manager implementation class which in case of JDBC is org.springframework.jdbc.datasource.DataSourceTransactionManager.
  2. <tx:annotation-driven/> tag is required to let Spring container know that annotation is used for transaction.
  3. Internally @Transactional annotation uses AOP proxies and proxy-target-class attribute controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If the proxy-target-class attribute is set to true, then class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, then standard JDK interface based proxies are created.
  4. xmlns:tx="http://www.springframework.org/schema/tx" is needed for tx namespace.
  5. Apart from that Datasource and JDBCTemplate are defined for connecting to DB and executing queries.
To run the Spring transaction management example you can use the following class.
public class App {

 public static void main(String[] args) {
   ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
         ("appcontext.xml");   
   EmployeeService empService = context.getBean("employeeServiceImpl", EmployeeServiceImpl.class); 
   empService.addEmployee(createEmployee());
   context.registerShutdownHook();   
 }
 
 // Method to create Employee object
 private static Employee createEmployee(){
  Employee emp = new Employee();
  Address addr = new Address();
  emp.setEmpId(101);
  emp.setEmpName("John");
  emp.setAge(25);
  // same as employee ID
  addr.setId(emp.getEmpId());
  addr.setAddrLine("Hunters Lane");
  addr.setCity("Princeton");
  emp.setAddress(addr);
  return emp;
 }
}

Output

INFO: Loading XML bean definitions from class path resource [appcontext.xml]
Aug 03, 2018 2:11:56 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Employee record inserted
Employee address record inserted
Aug 03, 2018 2:11:58 PM org.springframework.context.support.AbstractApplicationContext doClose

For checking that full transaction is rolled back or not, you can give some value while inserting address record which causes error. That should roll back the insertion to employee record too.

That's all for this topic Spring Transaction Management Example - @Transactional Annotation and JDBC. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Data Access in Spring Framework
  2. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example
  3. Autowiring Using Annotations in Spring
  4. Autodiscovery of Bean Using componenent-scan in Spring
  5. Spring Java Configuration Example Using @Configuration

You may also like-

  1. Using Spring Profiles to Switch Environment
  2. Difference Between component-scan And annotation-config in Spring
  3. Excluding Bean From Autowiring in Spring
  4. registerShutdownHook() Method in Spring Framework
  5. Invoking Getters And Setters Using Reflection - Java Program
  6. Deadlock in Java Multi-Threading
  7. BigDecimal in Java
  8. YARN in Hadoop

Wednesday, May 20, 2020

Spring Transaction Attributes - Propagation And Isolation Level Settings

When you declare a transaction in Spring transaction management you can define certain attributes for that transaction. These attributes define how the transaction will function.

Spring transaction attributes

Following attributes define the Spring transaction settings-

  1. Propagation
  2. Isolation level
  3. Time out
  4. Read only
  5. Roll back

Propagation settings in Spring transaction

Propagation behavior decides how a method will work in a transaction context. Transaction management in Spring framework defines seven propagation settings. These propagation settings are defined as final static int in org.springframework.transaction.TransactionDefinition interface.

  • PROPAGATION_REQUIRED- This propagation setting in Spring transaction management means that the method runs in a current transaction if exists. A new transaction is created if none exists.
  • PROPAGATION_REQUIRES_NEW- This propagation setting creates a new transaction, suspending the current transaction if one exists.
  • PROPAGATION_MANDATORY- This setting means that the method must run within a transaction. An exception is thrown if no current transaction exists.
  • PROPAGATION_SUPPORTS- This propagation setting supports a current transaction if exists and run with in it; if no transaction exists then the method executes non-transactionally.
  • PROPAGATION_NOT_SUPPORTED- This propagation setting means that the method doesn't support a transaction. If a transaction exits it is suspended when the method is executed.
  • PROPAGATION_NEVER- This propagation setting doesn't support a transaction. An exception is thrown if transaction exists.
  • PROPAGATION_NESTED- This propagation setting means that the method runs in a nested transaction if there is an existing transaction. If no transaction exists then this setting behaves like PROPAGATION_REQUIRED.

Isolation levels in Spring transaction

This property defines the extent to which this transaction is isolated from the work of other concurrent transactions. Before going into isolation levels defined by Spring transaction management, let’s see what problems may occur due to concurrent transactions.

Dirty read- This situation occurs when a transaction reads the data that is written but not committed by another transaction. As example Transaction T1 reads a row that is updated by Transaction T2 but not yet committed. Later T2 is rolled back which means T1 has read the data which is not valid now.

Non-repeatable reads- This scenario occurs when a transaction reads the same data twice and gets a different value every time. As example transaction T1 reads a row, another transaction T2 updates the same row and commits. T1 reads the same row again and gets a different value.

Phantom reads- In this scenario a transaction executes the same query to read a set of rows and gets additional set of rows in different executions. As example Transaction T1 executes a query to fetch some rows based on some condition, transaction T2 inserts rows that satisfies that condition. T1 runs the query again and gets the additional rows in next execution of the same query.

To mitigate the problems because of these scenarios Spring transaction management defines isolation levels to keep a transaction isolated from other concurrent transactions. Isolation levels as defined in Spring transaction management are as follows, these isolation level settings are defined as final static int in org.springframework.transaction.TransactionDefinition interface.
  • ISOLATION_DEFAULT- This setting means that the default isolation level of the underlying datastore is used.
  • ISOLATION_READ_UNCOMMITTED- This level allows a row changed by one transaction to be read by another transaction before any changes in that row have been committed. Using this setting means that dirty reads, non-repeatable reads and phantom reads can occur.
  • ISOLATION_READ_COMMITTED- This isolation level prohibits a transaction from reading a row with uncommitted changes in it. Using this setting means non-repeatable reads and phantom reads can occur only dirty reads are prevented.
  • ISOLATION_REPEATABLE_READ-This level prohibits a transaction from reading a row with uncommitted changes in it, and it also prohibits the situation where one transaction reads a row, a second transaction alters the row, and the first transaction re-reads the row, getting different values the second time. Using this setting means dirty reads and non-repeatable reads are prevented, phantom reads can occur.
  • ISOLATION_SERIALIZABLE- Using this isolation level means dirty reads, non-repeatable reads and phantom reads all are prevented.

Time out

You can define a time interval in seconds for the transaction to finish. If a transaction keeps running for a long time rather than keep on waiting for transaction to finish, you can provide time out in seconds. Transaction will automatically roll back after those many seconds are elapsed and it has not finished.

Note that timeout settings will not get applied unless an actual new transaction gets started. As only PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW and PROPAGATION_NESTED can cause that, it usually doesn't make sense to specify those settings in other cases.

Read only

By using read only property with the transaction you indicate that the transaction will only read the data won’t modify it. This property provides a chance to optimize transaction.

Roll back

Using this setting you can define for which exceptions transaction has to be rolled back. By default, transactions are rolled back only on runtime exceptions. Using roll back property you can provide specific exceptions (both checked exceptions and runtime exceptions) for which transaction has to be rolled back.

You can even define the no roll back rules specifying the exceptions for which the transaction should not be rolled back.

That's all for this topic Spring Transaction Attributes - Propagation And Isolation Level Settings. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Transaction Management JDBC Example Using @Transactional Annotation
  2. Select Query Using NamedParameterJDBCTemplate in Spring Framework
  3. Transaction in Java-JDBC
  4. Connection Pooling With Apache DBCP Spring Example
  5. Spring Web MVC Tutorial

You may also like-

  1. How to Inject Prototype Scoped Bean in Singleton Bean
  2. registerShutdownHook() Method in Spring Framework
  3. Run Time Injection Using Spring Expression Language(SpEL)
  4. Using Conditional Annotation in Spring Framework
  5. How to Create Password Protected Zip File in Java
  6. ThreadLocal Class in Java
  7. Type Erasure in Java Generics
  8. Uber Mode in Hadoop

Monday, May 18, 2020

Transaction Management in Spring

This post gives an overview of Spring transaction management, how abstraction is achieved in Spring transaction and how to do programmatic transaction management or declarative transaction management in Spring.


What is transaction

In an application transaction is a sequence of events with all or none proposition. That is either all the events participating in the transaction should happen or none. Transaction demarcates the boundaries and all the statements with in those boundaries are bound by all or none proposition and executed as a single unit of work.

Problems with managing transactions

If you manage transaction on your own or use EJB container managed transaction you choose the transaction as per your requirement i.e. if your using JDBC then you choose the transaction management API for JDBC, for Hibernate you will choose the hibernate transaction management API and for Application server with global transaction you will go with JTA (Java transaction API).

With this approach, if you are using global transactions, where you have multiple transactional resources (like relational databases and message queues) you will manage transaction through JTA.

If you are using local transactions (like a transaction associated with a JDBC connection) you will use JDBC transaction management API. Problem with local transactions is that they cannot work across multiple transactional resources. For example, code that manages transactions using a JDBC connection cannot run within a global JTA transaction. Another problem with local transactions is that they are invasive i.e. you will have all transaction code with in your code.

As example with JDBC transaction you will have something like following in your code.

try{
 connection.setAutoCommit(false);

 statements that are part of transaction
 ---
 ---

 connection.commit(); // for committing transaction
}catch(SQLException exp){
 // transaction rollback
 connection.rollback();
}

Transaction Management in Spring

Spring Framework provides a consistent abstraction for transaction management. Spring transaction management acts as an abstract layer hiding the underlying transaction management API thus providing a consistent programming model across different transaction APIs such as Java Transaction API(JTA), JDBC, Hibernate, and Java Persistence API (JPA).

With Spring transaction management you write your code once and it can be used in different transaction management strategies in different environments.

Spring transactions are also a significant improvement over the EJB transactions as you can use POJOs with Spring transactions. You don’t even need an Application server for Spring transactions unless you are using distributed transactions in which case you need JTA capabilities.

How abstraction is achieved in Spring transaction management

Abstraction in Spring transaction management is achieved through org.springframework.transaction.PlatformTransactionManager interface.

public interface PlatformTransactionManager {
 TransactionStatus getTransaction(TransactionDefinition definition)
             throws TransactionException;
 void commit(TransactionStatus status) throws TransactionException;
 void rollback(TransactionStatus status) throws TransactionException;
}

In the interface, getTransaction() method returns a TransactionStatus object which represents the status of a transaction, it might represent a new transaction or an existing transaction if a matching transaction exists. The parameter passed in getTransaction() method is an instance of TransactionDefinition.

TransactionDefinition defines the properties of the Spring transaction, which are as follows.

  • Propagation- Defines the propagation behavior of the transaction. For example you can specify a behavior so that code can continue running in the existing transaction or the existing transaction can be suspended and a new transaction created.
  • Isolation- This property defines the extent to which this transaction is isolated from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?
  • Timeout- How long this transaction runs before timing out and being rolled back automatically by the underlying transaction infrastructure.
  • Read-only status- A read-only transaction can be used when your code reads but does not modify data.

Refer Spring Transaction Attributes- Propagation And Isolation Level Settings to know about the various propagation and isolation level settings in the Spring transaction management.

Defining Transaction manager in Spring transactions

As we have seen it is the PlatformTransactionManager through which the transaction is abstracted in Spring transaction management but you do need to define the correct PlatformTransactionManager implementation.

PlatformTransactionManager implementations normally require knowledge of the environment in which they work: JDBC, JTA, Hibernate, and so on. Following are the implementation classes for different environments.

PlatformTransactionManager implementations in Spring framework

  • DataSourceTransactionManager- PlatformTransactionManager implementation for a single JDBC DataSource.
  • HibernateTransactionManager- PlatformTransactionManager implementation for a single Hibernate SessionFactory.
  • JmsTransactionManager- PlatformTransactionManager implementation for a single JMS ConnectionFactory.
  • JpaTransactionManager- PlatformTransactionManager implementation for a single JPA EntityManagerFactory.
  • JtaTransactionManager- PlatformTransactionManager implementation for JTA, delegating to a backend JTA provider.
  • WebLogicJtaTransactionManager- Special JtaTransactionManager variant for BEA WebLogic (9.0 and higher).
  • WebSphereUowTransactionManager- WebSphere-specific PlatformTransactionManager implementation that delegates to a UOWManager instance
Here are some examples showing how TransactionManager can be defined for different environments.

TransactionManager For JDBC in Spring

Defined by having a reference to the defined DataSource.

<bean id="txManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

TransactionManager For Hibernate in Spring

<bean id="txManager" class=
"org.springframework.orm.hibernate5.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

TransactionManager For JPA in Spring

<bean id="txManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
  <propertyname="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

TransactionManager For JTA in Spring

<bean id="txManager" class=
"org.springframework.transaction.jta.JtaTransactionManager" />

Spring Transaction management types

Spring Transaction management has support for both programmatic transaction management and declarative transaction management.

Programmatic transaction management

Spring Framework provides two means of programmatic transaction management-

  • Using TransactionTemplate.
  • Using a PlatformTransactionManager implementation directly.

Mostly declarative transaction that too using annotation is used so we'll focus on that. If you want to use TransactionTemplate then you can configure it as follows by providing the reference of the Transaction manager.

<propertyname="transactionTemplate">
<bean class="org.springframework.transaction.support.
TransactionTemplate">
<property name="transactionManager"
ref="txManager" />
</bean>
</property>

Declarative transaction management in Spring

By using Declarative transaction for Spring transaction management you keep transaction management separate from the business code. You can define declarative transactions using annotations or XML based configuration using AOP.

The annotation used for Declarative transaction management is @Transactional annotation. You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class.

To make Spring framework aware of the @Transactional annotation you will have to define <tx:annotation-driven/> element in your XML configuration.

<tx:annotation-driven transaction-manager="txManager"/>

If you using Java configuration then you can enable @Transactional annotation support by adding @EnableTransactionManagement to your config class.

@Configuration
@EnableTransactionManagement
public class AppConfig{
    ...
    ...
}

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces.

@Transactional settings in Spring framework

You can provide transaction properties like propagation behavior, isolation level along with @Transactional annotation. Full list of the properties of the @Transactional annotation are as follows-

  • propagation- Optional propagation setting.
  • isolation- Optional isolation level. Only applicable to propagation REQUIRED or REQUIRES_NEW.
  • timeout- Optional transaction timeout. Only applicable to propagation REQUIRED or REQUIRES_NEW. Defined in seconds using an int value.
  • readOnly- Read/write vs. read-only transaction. Only applicable to REQUIRED or REQUIRES_NEW.
  • rollbackFor- Optional array of exception classes that must cause rollback.
  • rollbackForClassName- Optional array of names of exception classes that must cause rollback.
  • noRollbackFor- Optional array of exception classes that must not cause rollback.
  • noRollbackForClassName- Optional array of names of exception classes that must not cause rollback.
The default @Transactional settings are as follows:
  • Propagation setting is PROPAGATION_REQUIRED.
  • Isolation level is ISOLATION_DEFAULT.
  • Transaction is read/write.
  • Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
  • Any RuntimeException triggers rollback, and any checked Exception does not.

Example using @Transactional annotation

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public class TestService implements FooService {
 public Foo getValue(String Id) {
  // do something
 }
 // these settings have precedence for this method
 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, timeout=60, rollbackFor=ValueNotFoundException.class)
 public void updateValue(Person person) {
  // do something
 }
}

Here at the class level TestService class is annotated with @Transactional annotation which is for all the methods in the class that all the methods will support transaction and will be read only. Method updateValue overrides it by having its own @Transactional annotation which requires a new transaction, read only is false and transaction is rolled back if ValueNotFoundException is thrown.

That's all for this topic Transaction Management in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Transaction Management JDBC Example Using @Transactional Annotation
  2. Data Access in Spring Framework
  3. Insert\Update Using NamedParameterJDBCTemplate in Spring Framework
  4. Spring MVC Form Example With Bean Validation
  5. Spring Batch Processing Using JDBCTemplate batchUpdate() Method

You may also like-

  1. Difference Between component-scan And annotation-config in Spring
  2. How to Inject Null And Empty String Values in Spring
  3. Internationalization (i18n) Using MessageSource in Spring
  4. Circular Dependency in Spring Framework
  5. Heap Memory Allocation in Java
  6. Stream API in Java 8
  7. Creating Custom Exception Class in Java
  8. Installing Hadoop on a Single Node Cluster in Pseudo-Distributed Mode

Wednesday, May 13, 2020

Difference Between @Controller And @RestController Annotations in Spring

In this post we’ll see the difference between @Controller and @RestController annotations in Spring framework.


@Controller annotation in Spring

In a Spring web MVC project generally a view technology like JSP, Freemarker, Thymeleaf is used to render the view. In that case from a Controller method, model is created and a logical view name is returned which is mapped to a view using the configured ViewResolver.

You may also return the object itself from the Controller method, in that case object data is written to the HTTP response body as JSON/XML. For that you need to use the annotation @ResponseBody explicitly which indicates a method return value should be bound to the web response body.

@RestController annotation in Spring

With RESTful web services interchange of data happens mostly as JSON or XML. In case you are writing a Spring REST service you will have to use @ResponseBody annotation along with the @Controller annotation to indicate that the returned object has to be serialized to the response body.

Unlike Spring Web MVC where mostly controller methods return ModelAndView, with Spring REST services it is the object itself which is returned. So Spring framework from version 4 has introduced a convenience annotation @RestController which combines both @Controller and @ResponseBody annotations. In a controller class annotated with @RestController all the @RequestMapping methods assume @ResponseBody semantics by default.

Following two types are same in Spring MVC.

@Controller
@ResponseBody
public class MessageController {
 ..
 ..
}
@RestController
public class MessageController {
 ..
 ..
}

Note that when @ResponseBody annotation is used on a method, return is serialized to the response body through an HttpMessageConverter.

Concrete implementations of the HttpMessageConverter for the main media (mime) types are provided in the Spring framework and are registered by default with the RestTemplate on the client-side and with RequestMethodHandlerAdapter on the server-side. Appropriate implementation of the HttpMessageConverter based on the mime type is chosen for converting the object.

@Controller Vs @RestController in Spring

1- @Controller annotation is used in Spring Web MVC project where model data is rendered using a view.
@RestController is used in RESTful web services where return value (which is mostly an object) is bound to the response body.

2- With classes annotated with @Controller annotation if you want return value to be converted through HttpMessageConverters and written to the response you will have to annotate the class with an extra annotation @ResponseBody or you can annotate individual handler methods with in the controller class with @ResponseBody annotation.
@RestController annotation is the combination of @Controller + @ResponseBody. With @RestController annotation it is the default behavior that the result will be written to the response body.

3- With @Controller annotation you still have that control that you can annotate individual methods with @ResponseBody annotation.
With @RestController annotation all the handler methods of the class write their result to the response body.

@Controller with @ResponseBody Spring MVC example

@Controller
public class MessageController {
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public String showHome(Model model) {
  model.addAttribute(new User());
  model.addAttribute("message", "Spring MVC example");
  return "home";
 }

 @RequestMapping(value = "/getUser/{userId}", method = RequestMethod.GET, produces="application/json")
 @ResponseBody
 public User getUser(@PathVariable("userId") String userId) {  
  return findUserById(userId);
 }

 // Dummy method to find user
 private User findUserById(String userId) {
  System.out.println("User ID " + userId);
  User user = new User();
  user.setUserId(userId);
  user.setFirstName("Leonard");
  user.setLastName("Nimoy");
  return user;
 }
}

As you can see in this controller class first method showHome() is a typical Spring web MVC handler method that returns a logical view name which resolves to home.jsp because of the following configuration.

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
</bean>

Second method getUser() is annotated with @ResponseBody annotation. Note that using the produces attribute it is also indicated that the media type is JSON.

You will need to add the following Maven dependency for JSON conversion-

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.6</version>
</dependency>

which adds the following jars.

jackson-databind-2.9.6.jar
jackson-annotations-2.9.0.jar
jackson-core-2.9.6.jar

Running it using the URL- http://localhost:8080/springmvc-config/getUser/101 after deployment gives the following result.

@Controller Vs @RestController Spring

@RestController annotation - Spring example

If we have to write the same controller class as a Rest service using @RestController annotation then there is no need to annotate the getUser() method explicitly with the @ResponseBody annotation.

@RestController
public class MessageController { 
 @RequestMapping(value = "/getUser/{userId}", method = RequestMethod.GET, produces="application/json")
 public User getUser(@PathVariable("userId") String userId) {  
  return findUserById(userId);
 }
 
 // Dummy method to find user
 private User findUserById(String userId) {
  System.out.println("User ID " + userId);
  User user = new User();
  user.setUserId(userId);
  user.setFirstName("Leonard");
  user.setLastName("Nimoy");
  return user;
 }
}

That's all for this topic Difference Between @Controller And @RestController Annotations in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring MVC Redirect Example
  2. Spring Transaction Management Example - @Transactional Annotation and JDBC
  3. Spring Batch Processing With List of Objects in batchUpdate() Method
  4. Spring NamedParameterJdbcTemplate Select Query Example
  5. Spring Java Configuration Example Using @Configuration

You may also like-

  1. Spring Profiles With Examples
  2. How to Inject Null And Empty String Values in Spring
  3. Spring util-namespace Example For Wiring Collection
  4. Injecting Inner Bean in Spring
  5. Difference Between ArrayList And LinkedList in Java
  6. Lambda Expressions in Java
  7. Array in Java With Examples
  8. How to Read And Write Parquet File in Hadoop