title: Spring data @Transactional not roll back
body: <p>I develops my first application using Spring MVC and Spring JPA. I get a problem when using @Transactional annotation. I annotate one of my service methods with @Transactional and I throw exception in that method because I expect it to be rolled back, but it do not.</p>
  
  <p>here is my configuration files and my class files content:</p>
  
  <p>app-context.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
  &lt;beans xmlns="http://www.springframework.org/schema/beans" 
      xmlns:context="http://www.springframework.org/schema/context" 
      xmlns:jdbc="http://www.springframework.org/schema/jdbc" 
      xmlns:tx="http://www.springframework.org/schema/tx" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:jpa="http://www.springframework.org/schema/data/jpa"
      xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd   http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"&gt;
  
      &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt;
  
      &lt;context:component-scan base-package="id.co.cslgroup"/&gt;
      &lt;jpa:repositories base-package="id.co.cslgroup"/&gt;
  
      &lt;bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource"&gt;
          &lt;property name="driverClassName" value="com.mysql.jdbc.Driver"/&gt;
          &lt;property name="url" value="${database.url}"/&gt;
          &lt;property name="username" value="${database.username}"/&gt;
          &lt;property name="password" value="${database.password}"/&gt;
          &lt;property name="testOnBorrow" value="true"/&gt;
          &lt;property name="testOnReturn" value="true"/&gt;
          &lt;property name="testWhileIdle" value="true"/&gt;
          &lt;property name="timeBetweenEvictionRunsMillis" value="1800000"/&gt;
          &lt;property name="numTestsPerEvictionRun" value="3"/&gt;
          &lt;property name="minEvictableIdleTimeMillis" value="1800000"/&gt;
          &lt;property name="validationQuery" value="SELECT 1"/&gt;
          &lt;property name="defaultAutoCommit" value="false"/&gt;
      &lt;/bean&gt;
      &lt;bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"&gt;
          &lt;property name="entityManagerFactory" ref="entityManagerFactory"/&gt;
      &lt;/bean&gt;
      &lt;bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"&gt;
          &lt;property name="persistenceUnitName" value="kms-pu"/&gt;
          &lt;property name="dataSource" ref="dataSource"/&gt;
          &lt;property name="jpaVendorAdapter" ref="hibernateJpaAdapter"/&gt;
      &lt;/bean&gt;
  
      &lt;bean id="customUserDetailsService" class="id.co.cslgroup.kms.svc.CustomUserDetailsService" /&gt;
      &lt;bean id="hibernateJpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/&gt;
  
      &lt;context:property-placeholder location="classpath:/META-INF/database.properties"/&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <p>web.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;
  
      &lt;!-- The definition of the Root Spring Container shared by all Servlets and Filters --&gt;
      &lt;context-param&gt;
          &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
          &lt;param-value&gt;
              classpath:/META-INF/spring/app-context.xml 
              /WEB-INF/spring/security-app-context.xml
                      /WEB-INF/spring/collection-context.xml
          &lt;/param-value&gt;
      &lt;/context-param&gt;
  
      &lt;filter&gt;
          &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
          &lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
      &lt;/filter&gt;
  
      &lt;filter-mapping&gt;
        &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
      &lt;/filter-mapping&gt;
  
      &lt;!-- Creates the Spring Container shared by all Servlets and Filters --&gt;
      &lt;listener&gt;
          &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
      &lt;/listener&gt;
  
          &lt;!-- place constraints on a single user's ability to log in to your application --&gt;
          &lt;listener&gt;
              &lt;listener-class&gt;
                  org.springframework.security.web.session.HttpSessionEventPublisher
              &lt;/listener-class&gt;
          &lt;/listener&gt;
  
      &lt;!-- Processes application requests --&gt;
      &lt;servlet&gt;
          &lt;servlet-name&gt;kmsServlet&lt;/servlet-name&gt;
          &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
          &lt;init-param&gt;
              &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
              &lt;param-value&gt;/WEB-INF/spring/servlet-context.xml&lt;/param-value&gt;
          &lt;/init-param&gt;   
          &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
      &lt;/servlet&gt;
  
      &lt;servlet-mapping&gt;
          &lt;servlet-name&gt;kmsServlet&lt;/servlet-name&gt;
          &lt;url-pattern&gt;/&lt;/url-pattern&gt;
      &lt;/servlet-mapping&gt;
  &lt;/web-app&gt;
  </code></pre>
  
  <p>servlet-context.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;beans:beans xmlns="http://www.springframework.org/schema/mvc"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:beans="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"&gt;
  
      &lt;!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --&gt;
  
      &lt;!-- Enables the Spring MVC @Controller programming model --&gt;
      &lt;annotation-driven conversion-service="conversionService"/&gt;
  
      &lt;!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --&gt;
      &lt;resources mapping="/resources/**" location="/resources/" /&gt;
  
      &lt;!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --&gt;
      &lt;beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
          &lt;beans:property name    ="prefix" value="/WEB-INF/views/" /&gt;
          &lt;beans:property name="suffix" value=".jsp" /&gt;
      &lt;/beans:bean&gt;
  
  
  
          &lt;beans:bean id="conversionService"
              class="org.springframework.context.support.ConversionServiceFactoryBean"&gt;
            &lt;beans:property name="converters"&gt;
                &lt;beans:list&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.AttributeConverter"/&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.KeyClassConverter"/&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.KeyTypeConverter"/&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.KeyProfileConverter"/&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.StringToDateConverter"/&gt;
                    &lt;beans:bean class="id.co.cslgroup.kms.svc.StringToIntegerConverter"/&gt;
                &lt;/beans:list&gt;
            &lt;/beans:property&gt;
        &lt;/beans:bean&gt;
      &lt;context:component-scan base-package="id.co.cslgroup" /&gt;    
  &lt;/beans:beans
  </code></pre>
  
  <p>></p>
  
  <p>persistence.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
  &lt;persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"&gt;
  &lt;persistence-unit name="kms-pu" transaction-type="RESOURCE_LOCAL"&gt;
          &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
          &lt;properties&gt;
              &lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/&gt;
              &lt;!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database --&gt;
              &lt;property name="hibernate.hbm2ddl.auto" value="update"/&gt;
              &lt;property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/&gt;
              &lt;property name="hibernate.connection.charSet" value="UTF-8"/&gt;
              &lt;!-- Uncomment the following two properties for JBoss only --&gt;
              &lt;!-- property name="hibernate.validator.apply_to_ddl" value="false" /--&gt;
              &lt;!-- property name="hibernate.validator.autoregister_listeners" value="false" /--&gt;
          &lt;/properties&gt;
      &lt;/persistence-unit&gt;
  &lt;/persistence&gt;
  </code></pre>
  
  <p>AttributeController.java</p>
  
  <pre><code>@Controller
  @RequestMapping(value="/attribute")
  public class AttributeController {
  
      @Autowired
      private AttributeService attService;
  
      @RequestMapping(value = "/save", method = RequestMethod.POST)
      public String save(@ModelAttribute("attribute") @Valid AttributeMasterForm attr,BindingResult result,Model model,@RequestParam("id") Long attID,HttpServletRequest httpRequest)
      {
  
          Map paramMap = httpRequest.getParameterMap();
          String[] frmTitlePar = (String[]) paramMap.get("formTitle");
  
          if(result.hasErrors()){
              model.addAttribute("formTitle",frmTitlePar[0]);
              model.addAttribute("id", attID);
              return "attribute/add";
          }
  
          System.out.println("Status: " + attr.getStatus());
  
          try{
              if(attr.getStatus() == null)
                  attr.setStatus(false);
  
              if(attID != null){    
                  attr = attService.edit(attr,attID);
              }
              else{
                  attr = attService.save(attr);
              }
          }
          catch(Exception e){
              e.printStackTrace();
              model.addAttribute("violateMsg", "Constraint Violation");
              model.addAttribute("formTitle",frmTitlePar[0]);
              model.addAttribute("id", attr.getId());
              return "attribute/add";
          }
          return "redirect:/attribute/show?id="+attr.getId();
      }
  }
  </code></pre>
  
  <p>AttributeRepository.java</p>
  
  <pre><code>public interface AttributeRepository extends JpaRepository&lt;Attribute, Long&gt; {
  }
  </code></pre>
  
  <p>AttributeService.java</p>
  
  <pre><code>@Service
  @Transactional
  public class AttributeService {
  @Autowired
      private AttributeRepository attributeRepository;
  
  @Transactional(readOnly=false,propagation= Propagation.REQUIRES_NEW,rollbackFor=Exception.class)
      public AttributeMasterForm save(AttributeMasterForm attForm) throws Exception{
          Attribute t = new Attribute();
          AttributeMasterForm masterForm = new AttributeMasterForm();
          //transfer value from master form to entity
          t = updateValue(t,attForm);
          //persist to database
          t = attributeRepository.save(t);
  
          if(t.getId() &gt; 1){
              throw new Exception();
          }
  
          return this.convertToMasterForm(t);
      }
  
  private AttributeMasterForm convertToMasterForm(Attribute attr){
              AttributeMasterForm masterForm = new AttributeMasterForm();
              masterForm.setId(attr.getId());
              masterForm.setCode(attr.getCode());
              masterForm.setName(attr.getName());
              masterForm.setStatus(attr.getStatus());
  
          return masterForm;
      }
  
  private Attribute updateValue(Attribute attr,AttributeMasterForm attForm){
              attr.setCode(attForm.getCode());
              attr.setName(attForm.getName());
              attr.setStatus(attForm.getStatus());
  
              return attr;
          }
  }
  </code></pre>
  
  <p>Attribute.java</p>
  
  <pre><code>package id.co.cslgroup.kms.entity;
  
  import java.util.Collection;
  import java.util.Date;
  import java.util.Set;
  import javax.persistence.CascadeType;
  
  import javax.persistence.Column;
  import javax.persistence.Entity;
  import javax.persistence.FetchType;
  import javax.persistence.JoinColumn;
  import javax.persistence.JoinTable;
  import javax.persistence.ManyToMany;
  import javax.persistence.OneToMany;
  import javax.persistence.PrePersist;
  import javax.persistence.PreUpdate;
  import javax.persistence.Temporal;
  import javax.persistence.Version;
  import javax.validation.constraints.NotNull;
  import org.hibernate.validator.constraints.NotEmpty;
  
  
  import org.springframework.data.jpa.domain.AbstractPersistable;
  
  @Entity
  public class Attribute extends AbstractPersistable&lt;Long&gt; {
  
      @Column(nullable = false, unique = true)
      @NotEmpty
      @NotNull
      private String code;
      @Column(nullable = false)
      @NotEmpty
      @NotNull
      private String name;
  
      @OneToMany(fetch= FetchType.LAZY, mappedBy = "pk.attribute")
      private Collection&lt;ProfileAttribute&gt; profileAttribute;
  
      @Column(nullable = false)
      @Temporal(javax.persistence.TemporalType.DATE)
      private Date createTime;
      @Column(nullable = false)
      private String createBy;
      @Column(nullable = true)
      @Temporal(javax.persistence.TemporalType.DATE)
      private Date updateTime;
      @Column(nullable = true)
      private String updateBy;
      @Column(nullable = false)
      private Boolean status;
      @Version
      @Column
      private Long version = 0L;
  
  //        @ManyToMany(cascade=CascadeType.ALL)
  //        @JoinTable(name = "key_attributes",
  //            joinColumns = {@JoinColumn(name="attribute_id")},
  //            inverseJoinColumns = {@JoinColumn(name="key_table_id")}
  //        )
  //        private Set&lt;KeyTable&gt; keytables;
  //        
  //        public Set&lt;KeyTable&gt; getKeyTables(){
  //            return keytables;
  //        }
  //        
  //        public void setKeyTables(Set&lt;KeyTable&gt; kt){
  //            this.keytables = kt;
  //        }
  //        @Transient
  //        private String[] testArr;
  //        
  //        public String[] getTestArr() {
  //      return testArr;
  //  }
  //
  //  public void setTestArr(String[] ta) {
  //      this.testArr = ta;
  //  }
      public String getCode() {
          return code;
      }
  
      public void setCode(String code) {
          this.code = code;
      }
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public Boolean getStatus() {
          return status;
      }
  
      public void setStatus(Boolean status) {
          this.status = status;
      }
  
      public String getCreateBy() {
          return createBy;
      }
  
      public void setCreateBy(String createBy) {
          this.createBy = createBy;
      }
  
      public String getUpdateBy() {
          return updateBy;
      }
  
      public void setUpdateBy(String updateBy) {
          this.updateBy = updateBy;
      }
  
      public Date getCreateTime() {
          return createTime;
      }
  
      public Date getUpdateTime() {
          return updateTime;
      }
  
      public Long getVersion() {
          return version;
      }
  
      @PrePersist
      private void prePersist() {
          this.createBy = "Admin";
          this.createTime = new Date();
      }
  
      @PreUpdate
      private void preUpdate() {
          this.updateBy = "Admin";
          this.updateTime = new Date();
      }
  
      /**
       * @return the keyProfiles
       */
          public Collection&lt;ProfileAttribute&gt; getProfileAttribute() {
          return profileAttribute;
      }
  
      /**
       * @param keyProfiles the keyProfiles to set
       */
      public void setProfileAttribute(Collection&lt;ProfileAttribute&gt; profileAttribute) {
          this.profileAttribute = profileAttribute;
      }
  }
  </code></pre>
  
  <p>AttributeMasterForm.java</p>
  
  <pre><code>/*
   * To change this template, choose Tools | Templates
   * and open the template in the editor.
   */
  package id.co.cslgroup.kms.model;
  
  import java.util.Date;
  import javax.validation.constraints.NotNull;
  import org.hibernate.validator.constraints.NotEmpty;
  
  /**
   *
   * @author supriadi
   */
  public class AttributeMasterForm {
  
      private Long id;
  
      @NotEmpty
      @NotNull
      private String code;
  
      @NotEmpty
      @NotNull
      private String name;
  
      private Date createTime;
      private String createBy;
      private Date updateTime;
      private String updateBy;
  
      private Boolean status;
  
      /**
       * @return the id
       */
      public Long getId() {
          return id;
      }
  
      /**
       * @param id the id to set
       */
      public void setId(Long id) {
          this.id = id;
      }
  
      /**
       * @return the code
       */
      public String getCode() {
          return code;
      }
  
      /**
       * @param code the code to set
       */
      public void setCode(String code) {
          this.code = code;
      }
  
      /**
       * @return the name
       */
      public String getName() {
          return name;
      }
  
      /**
       * @param name the name to set
       */
      public void setName(String name) {
          this.name = name;
      }
  
      /**
       * @return the status
       */
      public Boolean getStatus() {
          return status;
      }
  
      /**
       * @param status the status to set
       */
      public void setStatus(Boolean status) {
          this.status = status;
      }
  
      /**
       * @return the createTime
       */
      public Date getCreateTime() {
          return createTime;
      }
  
      /**
       * @param createTime the createTime to set
       */
      public void setCreateTime(Date createTime) {
          this.createTime = createTime;
      }
  
      /**
       * @return the createBy
       */
      public String getCreateBy() {
          return createBy;
      }
  
      /**
       * @param createBy the createBy to set
       */
      public void setCreateBy(String createBy) {
          this.createBy = createBy;
      }
  
      /**
       * @return the updateTime
       */
      public Date getUpdateTime() {
          return updateTime;
      }
  
      /**
       * @param updateTime the updateTime to set
       */
      public void setUpdateTime(Date updateTime) {
          this.updateTime = updateTime;
      }
  
      /**
       * @return the updateBy
       */
      public String getUpdateBy() {
          return updateBy;
      }
  
      /**
       * @param updateBy the updateBy to set
       */
      public void setUpdateBy(String updateBy) {
          this.updateBy = updateBy;
      }
  }
  </code></pre>
  
  <p>In AttributeService.java, in save method, you can find:</p>
  
  <pre><code>t = attributeRepository.save(t);
  
  if(t.getId() &gt; 1){
              throw new Exception();
          }
  </code></pre>
  
  <p>So after I call save, I immediately throw an exception, but then I check the database and it did not rolled back.</p>
  
  <p>I really appreciate any help from you guys,
  Thanks!</p>