title: Using @Transactional: transaction get commited even if exception thrown
body: <p>I m using struts2 - spring 3.2.2 and mybatis.</p>
  
  <p>First of all my requirements are:</p>
  
  <p>Make a transaction management utility in which</p>
  
  <ol>
  <li>Transaction must be rolled back if any exception thrown in other statement of current transaction. (The other db operations may be performed through various classes, i.e. not in same class.)</li>
  </ol>
  
  <p>Following the requirements, i ve created simple program.
  my applicationContext.xml file:</p>
  
  <hr>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd"&gt;
  
      &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt;
          &lt;!-- Initialization for data source --&gt;
     &lt;bean id="dataSource" 
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
        &lt;property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/&gt;
        &lt;property name="url" value="jdbc:sqlserver://localhost;database=master;integratedSecurity=true;"/&gt;
        &lt;property name="username" value="Jaydeep"/&gt;
        &lt;property name="password" value="Acty#System123"/&gt;
     &lt;/bean&gt;
  
      &lt;bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&gt;
          &lt;property name="dataSource" ref="dataSource" /&gt;
  
          &lt;property name='mapperLocations' value='classpath*:test/xml/*.xml' /&gt;
      &lt;/bean&gt;
  
      &lt;bean class='org.mybatis.spring.mapper.MapperScannerConfigurer'&gt;
        &lt;property name='basePackage' value='test.dao' /&gt;
      &lt;/bean&gt;
  
      &lt;bean id='sqlSession' class='org.mybatis.spring.SqlSessionTemplate'&gt;
        &lt;constructor-arg index='0' ref='sqlSessionFactory' /&gt;
      &lt;/bean&gt;
  
     &lt;bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;
          &lt;property name="dataSource" ref="dataSource" /&gt;
      &lt;/bean&gt;
  
     &lt;bean id="serviceProvider"
        class="DataServiceProvider"&gt;
        &lt;property name="sqlSession"  ref="sqlSession" /&gt;    
     &lt;/bean&gt;
  
      &lt;bean id="updutil" class="MyUpdateUtil"&gt;
          &lt;property name="serviceProvider" ref="serviceProvider"&gt;&lt;/property&gt;
      &lt;/bean&gt;
  
  &lt;/beans&gt;
  </code></pre>
  
  <p>//DataServiceProvider.java</p>
  
  <pre><code>import org.apache.ibatis.session.SqlSession;
  import test.dao.DepartmentMapper;
  import test.dao.EmployeeMapper;
  
  public class DataServiceProvider {
      private SqlSession sqlSession;
      public DepartmentMapper getDeptMapper() {
          if(sqlSession != null)
              return sqlSession.getMapper(DepartmentMapper.class);
          else
              System.out.println("session null");
          return null;
      }
      public EmployeeMapper getEmpMapper() {
          if(sqlSession != null)
              return sqlSession.getMapper(EmployeeMapper.class);
          else
              System.out.println("session null");
          return null;
      }
  
      public SqlSession getSqlSession() {
          return sqlSession;
      }
  
      public void setSqlSession(SqlSession sqlSession) {
          this.sqlSession = sqlSession;
      }
  }
  </code></pre>
  
  <p>//Interface: fooService.java</p>
  
  <pre><code>import java.io.IOException;
  import java.lang.reflect.InvocationTargetException;
  import org.springframework.transaction.annotation.Transactional;
  import test.model.Department;
  
  @Transactional
  public interface fooService {
  
      public void update(boolean isThrow) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException;
  
      public void insert(Department dept) throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException;
  
      public void select() throws IOException;
  }
  </code></pre>
  
  <p>//Utility class in which all db related operations will be performed
  //MyUpdateUtil.java</p>
  
  <pre><code>import java.io.IOException;
  import java.lang.reflect.InvocationTargetException;
  import java.math.BigDecimal;
  import java.util.List;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.transaction.annotation.Transactional;
  import test.model.Department;
  import test.model.Employee;
  import test.model.EmployeeExample;
  
  @Transactional
  public class MyUpdateUtil implements fooService {
  
      public void update(boolean isThrow) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException  {
          System.out.println("Updating...................Transaction alive? ..." + StartTransAction.isActive());
          if(isThrow)
              throw new RuntimeException("simulate Error condition") ;
          Employee record = new Employee();
          EmployeeExample example = new EmployeeExample();
          example.createCriteria().andDeptidEqualTo(1L);
  
          record.setEmpid(1L);
          record.setDeptid(1L);
          record.setEmpname("jaydeep");
          record.setSalary(BigDecimal.valueOf(2000));
  
          getServiceProvider().getEmpMapper().updateByExampleWithBLOBs(record, example);
      }
      @Transactional
      public void insert(Department dept) throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
          System.out.println("Inserting....................Transaction alive? .." + StartTransAction.isActive());
          getServiceProvider().getDeptMapper().insert(dept);
      }
  
      public void select() throws IOException {
          System.out.println("Dept Info");
          List&lt;Department&gt; deptList = getServiceProvider().getDeptMapper().selectByExampleWithBLOBs(null);
          for(Department d : deptList) {
              System.out.println("Dept ID: " + d.getDeptid());
              System.out.println("Dept Name: " + d.getDeptname());
          }
          System.out.println("Emp Info");
          List&lt;Employee&gt; empList = getServiceProvider().getEmpMapper().selectByExampleWithBLOBs(null);
          for(Employee e : empList) {
              System.out.println("Emp ID: " + e.getEmpid());
              System.out.println("Dept ID: " + e.getDeptid());
              System.out.println("Emp Name: " + e.getEmpname());
          }
      }   
      @Autowired(required=true)
      private DataServiceProvider serviceProvider;
      public DataServiceProvider getServiceProvider() {
          return serviceProvider;
      }
  
      public void setServiceProvider(DataServiceProvider serviceProvider) {
          this.serviceProvider = serviceProvider;
      }
  }
  </code></pre>
  
  <p>//and the main action which executed when i click on link from jsp page....
  //StartTransAction.java</p>
  
  <pre><code>import java.io.IOException;
  import java.lang.reflect.InvocationTargetException;
  import java.util.Random;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  import test.model.Department;
  
  import com.opensymphony.xwork2.ActionSupport;
  
  
  public class StartTransAction extends ActionSupport {
      private static final long serialVersionUID = 1L;
  
      public String execute() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {      
          Department dept = new Department();
          dept.setDeptid(Long.valueOf(String.valueOf(new Random().nextInt(500))));
          dept.setDeptname("esb");
          System.out.println("before Insert..................Transaction alive? ...." + isActive());
          try {
              updutil.insert(dept);
  
              System.out.println("After Insert..................Transaction alive? ...." + isActive());
              updutil.select();
              updutil.update(true);
          } catch (Exception e) {
              System.out.println(e.toString());
          }finally{
              System.out.println("After Update.................Transaction alive? ....." + isActive());
              updutil.select();
          }
          return SUCCESS;
      }
      @Autowired
      fooService updutil;
  
      public fooService getUpdutil() {
          return new MyUpdateUtil();
      }
      public void setUpdutil(fooService updutil) {
          this.updutil = updutil;
      }
      private DataSourceTransactionManager transactionManager;
  
      public DataSourceTransactionManager getTransactionManager() {
          return transactionManager;
      }
      public void setTransactionManager(
              DataSourceTransactionManager transactionManager) {
          this.transactionManager = transactionManager;
      }   
  
      public static boolean isActive() throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException  {
          ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
           Class tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
           Boolean isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
           return isActive;
      }
  }
  </code></pre>
  
  <p>Now when i run the program... output is like this:</p>
  
  <p>before Insert.................Transaction alive? .....false <br>
  Inserting..................Transaction alive? ....true<br>
  After Insert................Transaction alive? ......false<br>
  Dept Info<br>
  Dept ID: 1<br>
  Dept Name: si<br>
  Dept ID: 251<br>
  Dept Name: esb<br>
  <strong><em>Dept ID: 293<br>
  Dept Name: esb</em></strong><br>
  Emp Info<br>
  Emp ID: 1<br>
  Dept ID: 1<br>
  Emp Name: s<br>
  Updating.................Transaction alive? .....true<br>
  java.lang.RuntimeException: simulate Error condition<br>
  After Update.................Transaction alive? .....false<br>
  Dept Info<br>
  Dept ID: 1<br>
  Dept Name: si<br>
  Dept ID: 251<br>
  Dept Name: esb<br>
  <strong><em>Dept ID: 293<br>
  Dept Name: esb</em></strong><br>
  Emp Info<br>
  Emp ID: 1<br>
  Dept ID: 1<br>
  Emp Name: s<br>
  <br>
  <hr>
  The bolder part is new record inserted.</p>
  
  <p><b> after the runtime exception thrown, i need the inserted record must be rolled back.</b> But as shown in output, the record get committed even if exception was thrown.
  As we can see, the transaction also continued in update() method, too.</p>
  
  <p>Please please help me achieving this. I tried a lot, but not working.
  if possible give me working code of above problem....</p>
  
  <hr>
  
  <p>EDIT:
  I replaced above code entirely.</p>
  
  <p>Now i have the following files:</p>
  
  <p>//applicationContext.xml:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd"&gt;
  
      &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt;
         &lt;!-- bean id="serviceProvider" class="DataServiceProvider"&gt;&lt;/bean--&gt;
          &lt;!-- Initialization for data source --&gt;
     &lt;bean id="dataSource" 
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
        &lt;property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/&gt;
        &lt;property name="url" value="jdbc:sqlserver://localhost;database=master;integratedSecurity=true;"/&gt;
        &lt;property name="username" value="Jaydeep"/&gt;
        &lt;property name="password" value="Acty#System123"/&gt;
  
     &lt;/bean&gt;
  
      &lt;bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&gt;
          &lt;property name="dataSource" ref="dataSource" /&gt;
          &lt;property name='mapperLocations' value='classpath*:test/xml/*.xml' /&gt;
      &lt;/bean&gt;
  
      &lt;bean class='org.mybatis.spring.mapper.MapperScannerConfigurer'&gt;
        &lt;property name='basePackage' value='test.dao' /&gt;
        &lt;property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /&gt;
      &lt;/bean&gt;
  
  
      &lt;bean id='sqlSession' class='org.mybatis.spring.SqlSessionTemplate'&gt;
        &lt;constructor-arg index='0' ref='sqlSessionFactory' /&gt;
      &lt;/bean&gt;
  
     &lt;bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;
          &lt;property name="dataSource" ref="dataSource" /&gt;
          &lt;property name="nestedTransactionAllowed" value="true" /&gt;
          &lt;property name="validateExistingTransaction" value="true" /&gt;
      &lt;/bean&gt;
  
      &lt;bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"&gt;
          &lt;constructor-arg index='0' ref='sqlSessionFactory' /&gt;
      &lt;/bean&gt;
  
      &lt;bean id="myService" class="service.MyService"&gt;
          &lt;property name="sqlSessionTemplate" ref="sqlSessionTemplate" /&gt;
      &lt;/bean&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <p>//StartTransAction.java</p>
  
  <pre><code>package com.acty;
  import java.lang.reflect.InvocationTargetException;
  import service.MyService;
  
  import com.opensymphony.xwork2.ActionSupport;
  
  public class StartTransAction extends ActionSupport {
      private static final long serialVersionUID = 1L;
  
      public String execute(){
          myService.startOperations();
          return SUCCESS;
      }
  
      public static boolean isActive() {
          ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
           Class tsmClass = null;
          try {
              tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
          } catch (ClassNotFoundException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
           Boolean isActive = null;
          try {
              isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
          } catch (IllegalAccessException | IllegalArgumentException
                  | InvocationTargetException | NoSuchMethodException
                  | SecurityException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
           return isActive;
      }
  
      private MyService myService;
  
      public void setMyService(MyService myService) {
          this.myService = myService;
      }
  }
  </code></pre>
  
  <p>and //MyService.java</p>
  
  <pre><code>package service;
  
  import java.util.List;
  import java.util.Scanner;
  
  import org.mybatis.spring.SqlSessionTemplate;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.EnableTransactionManagement;
  import org.springframework.transaction.annotation.Propagation;
  import org.springframework.transaction.annotation.Transactional;
  
  import test.dao.DepartmentMapper;
  import test.dao.EmployeeMapper;
  import test.model.Department;
  import test.model.Employee;
  import test.model.EmployeeExample;
  
  @Service
  @EnableTransactionManagement
  @Transactional(propagation=Propagation.REQUIRED)
  public class MyService {
      @Autowired
      private SqlSessionTemplate sqlSessionTemplate;
  
      public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
          this.sqlSessionTemplate = sqlSessionTemplate;
      }
      @Transactional(propagation=Propagation.REQUIRED)
      public void startOperations() {
          DepartmentMapper deptMapper = sqlSessionTemplate.getMapper(DepartmentMapper.class);
          EmployeeMapper empMapper = sqlSessionTemplate.getMapper(EmployeeMapper.class);
  
          System.out.println("Before Insert Dept" + com.acty.StartTransAction.isActive());
  
          this.select(deptMapper, empMapper);
  
          Department dept = new Department();
          //insert new dept
          Scanner sc = new Scanner(System.in);
          System.out.println("Enter dept id ");
          dept.setDeptid(sc.nextLong());
          System.out.println("Enter dept Name ");
          dept.setDeptname(sc.next());
  
          deptMapper.insert(dept);
  
          System.out.println("After Insert Dept" + com.acty.StartTransAction.isActive());
  
          this.select(deptMapper, empMapper);
  
          this.select(deptMapper, empMapper);
          //now update employee
  
          EmployeeExample example = new EmployeeExample();
          example.createCriteria().andEmpidEqualTo(1L);
  
          Employee emp = new Employee();
          emp.setEmpname("jjj");
  
          try {
          //empMapper.updateByExampleSelective(emp, example);
          empMapper.updateByExampleWithBLOBs(emp, example);
          }catch(Exception e) {
              e.printStackTrace();
          }
          System.out.println("After Update Emp");
  
          this.select(deptMapper, empMapper);
      }
      public void select(DepartmentMapper deptMapper, EmployeeMapper empMapper) {
          System.out.println("\nDeptartment\n");
          List&lt;Department&gt; deptList= deptMapper.selectByExampleWithBLOBs(null);
          for(Department de : deptList) {
              System.out.println(" Dept Id : " + de.getDeptid());
              System.out.println(" Dept Name : " + de.getDeptname());
          }
          System.out.println("\nEmployee\n");
          List&lt;Employee&gt; empList= empMapper.selectByExampleWithBLOBs(null);
          for(Employee emp : empList) {
              System.out.println(" Emp Id : " + emp.getEmpid());
              System.out.println(" Emp Name : " + emp.getEmpname());
          }
      }
  }
  </code></pre>
  
  <p>//Now im doing the things at service layer.
  All DAOs are in other package and i get it from injected by spring.</p>
  
  <p>Then also the trick is not working.
  Look the output:<br>
  Before Insert Dept  true<br>
  <br>
  Deptartment<br>
  <br>
   Dept Id : 1<br>
   Dept Name : si<br>
   Dept Id : 2<br>
   Dept Name : esb<br>
   Dept Id : 3<br>
  <br>
  Employee<br>
  <br>
   Emp Id : 1<br>
   Emp Name : kkkkk<br>
  Enter dept id <br>
  4<br>
  Enter dept Name <br>
  asdwe<br>
  After Insert Depttrue<br>
  <br>
  Deptartment<br>
  <br>
   Dept Id : 1<br>
   Dept Name : si<br>
   Dept Id : 2<br>
   Dept Name : esb<br>
   Dept Id : 3<br>
   Dept Name : esb<br>
   Dept Id : 4<br>
   Dept Name : asdwe<br></p>
  
  <p>-- here exception occurs <br>
  org.springframework.dao.DataIntegrityViolationException: </p>
  
  <h3>Error updating database.  Cause: com.microsoft.sqlserver.jdbc.SQLServerException: Ca</h3>
  
  <h2>.....</h2>
  
  <p>After Update Emp
  Deptartment<br>
  <br>
   Dept Id : 1<br>
   Dept Name : si<br>
   Dept Id : 2<br>
   Dept Name : esb<br>
   Dept Id : 3<br>
   Dept Name : esb<br>
   Dept Id : 4<br>
   Dept Name : asdwe<br></p>
  
  <p>...
  Look here , department inserted before, is not rolled back here.....
  (We can use rollback method for sqlSessionTemplate here, but then what is the use of spring automatic transaction management?? There will no sense by doing this, i believe!)
  Whats the problem, i really didnt get...</p>
  
  <p>Plz provide some working solution...</p>