2013-05-07 53 views
3

我使用Spring MVC和Spring JPA開發了我的第一個應用程序。使用@Transactional註釋時出現問題。我使用@Transactional註釋了我的一個服務方法,並在該方法中拋出異常,因爲我期望它回滾,但不會。Spring data @Transactional不回滾

這裏是我的配置文件和我的類文件的內容:

APP-context.xml中

<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<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"> 

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

    <context:component-scan base-package="id.co.cslgroup"/> 
    <jpa:repositories base-package="id.co.cslgroup"/> 

    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource"> 
     <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 
     <property name="url" value="${database.url}"/> 
     <property name="username" value="${database.username}"/> 
     <property name="password" value="${database.password}"/> 
     <property name="testOnBorrow" value="true"/> 
     <property name="testOnReturn" value="true"/> 
     <property name="testWhileIdle" value="true"/> 
     <property name="timeBetweenEvictionRunsMillis" value="1800000"/> 
     <property name="numTestsPerEvictionRun" value="3"/> 
     <property name="minEvictableIdleTimeMillis" value="1800000"/> 
     <property name="validationQuery" value="SELECT 1"/> 
     <property name="defaultAutoCommit" value="false"/> 
    </bean> 
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory"/> 
    </bean> 
    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> 
     <property name="persistenceUnitName" value="kms-pu"/> 
     <property name="dataSource" ref="dataSource"/> 
     <property name="jpaVendorAdapter" ref="hibernateJpaAdapter"/> 
    </bean> 

    <bean id="customUserDetailsService" class="id.co.cslgroup.kms.svc.CustomUserDetailsService" /> 
    <bean id="hibernateJpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> 

    <context:property-placeholder location="classpath:/META-INF/database.properties"/> 
</beans> 

的web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<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"> 

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> 
    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value> 
      classpath:/META-INF/spring/app-context.xml 
      /WEB-INF/spring/security-app-context.xml 
        /WEB-INF/spring/collection-context.xml 
     </param-value> 
    </context-param> 

    <filter> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
    </filter> 

    <filter-mapping> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 

    <!-- Creates the Spring Container shared by all Servlets and Filters --> 
    <listener> 
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 

     <!-- place constraints on a single user's ability to log in to your application --> 
     <listener> 
      <listener-class> 
       org.springframework.security.web.session.HttpSessionEventPublisher 
      </listener-class> 
     </listener> 

    <!-- Processes application requests --> 
    <servlet> 
     <servlet-name>kmsServlet</servlet-name> 
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
     <init-param> 
      <param-name>contextConfigLocation</param-name> 
      <param-value>/WEB-INF/spring/servlet-context.xml</param-value> 
     </init-param> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 

    <servlet-mapping> 
     <servlet-name>kmsServlet</servlet-name> 
     <url-pattern>/</url-pattern> 
    </servlet-mapping> 
</web-app> 

的servlet-context.xml的

<?xml version="1.0" encoding="UTF-8"?> 
<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"> 

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --> 

    <!-- Enables the Spring MVC @Controller programming model --> 
    <annotation-driven conversion-service="conversionService"/> 

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --> 
    <resources mapping="/resources/**" location="/resources/" /> 

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> 
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <beans:property name ="prefix" value="/WEB-INF/views/" /> 
     <beans:property name="suffix" value=".jsp" /> 
    </beans:bean> 



     <beans:bean id="conversionService" 
      class="org.springframework.context.support.ConversionServiceFactoryBean"> 
      <beans:property name="converters"> 
       <beans:list> 
        <beans:bean class="id.co.cslgroup.kms.svc.AttributeConverter"/> 
        <beans:bean class="id.co.cslgroup.kms.svc.KeyClassConverter"/> 
        <beans:bean class="id.co.cslgroup.kms.svc.KeyTypeConverter"/> 
        <beans:bean class="id.co.cslgroup.kms.svc.KeyProfileConverter"/> 
        <beans:bean class="id.co.cslgroup.kms.svc.StringToDateConverter"/> 
        <beans:bean class="id.co.cslgroup.kms.svc.StringToIntegerConverter"/> 
       </beans:list> 
      </beans:property> 
     </beans:bean> 
    <context:component-scan base-package="id.co.cslgroup" />  
</beans:beans 

>

的persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<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"> 
<persistence-unit name="kms-pu" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <properties> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/> 
      <!-- 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 --> 
      <property name="hibernate.hbm2ddl.auto" value="update"/> 
      <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> 
      <property name="hibernate.connection.charSet" value="UTF-8"/> 
      <!-- Uncomment the following two properties for JBoss only --> 
      <!-- property name="hibernate.validator.apply_to_ddl" value="false" /--> 
      <!-- property name="hibernate.validator.autoregister_listeners" value="false" /--> 
     </properties> 
    </persistence-unit> 
</persistence> 

AttributeController.java

@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(); 
    } 
} 

AttributeRepository.java

public interface AttributeRepository extends JpaRepository<Attribute, Long> { 
} 

AttributeService.java

@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() > 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; 
     } 
} 

Attribute.java

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<Long> { 

    @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<ProfileAttribute> 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<KeyTable> keytables; 
//   
//  public Set<KeyTable> getKeyTables(){ 
//   return keytables; 
//  } 
//   
//  public void setKeyTables(Set<KeyTable> 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<ProfileAttribute> getProfileAttribute() { 
     return profileAttribute; 
    } 

    /** 
    * @param keyProfiles the keyProfiles to set 
    */ 
    public void setProfileAttribute(Collection<ProfileAttribute> profileAttribute) { 
     this.profileAttribute = profileAttribute; 
    } 
} 

AttributeMasterForm.java

/* 
* 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; 
    } 
} 

在AttributeService.java,在保存方法,你可以找到:

t = attributeRepository.save(t); 

if(t.getId() > 1){ 
      throw new Exception(); 
     } 

我打電話救所以後,我立即拋出一個異常,但後來我檢查數據庫,並沒有回滾。

我真的很感謝你們的幫助, 謝謝!

+0

請在代碼中調用'AttributeService.save()'方法 – 2013-05-07 09:58:24

+0

我在AttributeController類中調用它。我編輯了我的問題,謝謝。 – 2013-05-07 11:00:21

+0

@ChrismaAndhika你能告訴我們AtributeRepositoy的實現嗎?你有沒有使用交易註釋呢?或者像內部提交的東西?你的電話代碼對我來說很不錯.. – 2013-05-07 11:04:47

回答

1

你的Attribute班沒有id字段。它是否來自AbstractPersistable<Long>你能告訴我你是如何註明ID字段的嗎?是Auto generated

根據上面的回答,可能有幾個可能的事情。 1.您Id不會比1更大和excepion從未拋出

我會建議嘗試用下面的代碼,讓我知道,如果即使它的事務不會回滾。

t = attributeRepository.save(t); 
throw new Exception(); 

也顯示出對id如何在映射代碼的Attribute class將有助於幫助你

而且您在哪裏如何調用了AttributeService Save方法也影響了交易。那部分代碼也會有幫助。

+0

id是來自AbstractPersistable ,它是自動生成的。我也調試AttributeService和拋出新的Exception();行被執行。我在AttributeController中調用save方法。 – 2013-05-07 10:52:57

+0

@ChrismaAndhika如何以及在哪裏調用了AttributeService保存方法也會影響事務。那部分代碼也會有幫助。你可以添加到問題 – 2013-05-07 11:00:31

相關問題