2014-01-29 49 views
1

以下是我的所有代碼。數據庫行未被創建。拋出異常。@交易註釋不起作用。數據庫行未創建

package com.rishi.app.models; 

import java.util.Collection; 

import javax.management.Query; 
import javax.persistence.Entity; 
import javax.persistence.EntityManager; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.PersistenceContext; 
import javax.persistence.PersistenceUnit; 
import javax.persistence.TypedQuery; 

@Entity 
public class Customer { 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    private int id; 
    private String firstName; 
    private String lastName; 

    protected Customer() {} 

    public Customer(String firstName, String lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

    @Override 
    public String toString() { 
     return String.format(
       "Customer[id=%d, firstName='%s', lastName='%s']", 
       id, firstName, lastName); 
    } 

} 


package com.rishi.app.repositories; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.transaction.Transactional; 

import org.springframework.stereotype.Repository; 

import com.rishi.app.models.Customer; 

@Repository 
public class CustomerRepository { 
    @PersistenceContext 
    private EntityManager em; 

    @Transactional 
    public void save(Customer c) { 
     em.persist(c); 
    } 
} 

package com.rishi.app.controllers; 

import java.text.DateFormat; 
import java.util.Date; 
import java.util.Locale; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.PersistenceContext; 
import javax.transaction.Transactional; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 

import com.rishi.app.models.Customer; 
import com.rishi.app.repositories.CustomerRepository; 

/** 
* Handles requests for the application home page. 
*/ 
@Controller 
public class HomeController { 
    @PersistenceContext 
    EntityManager entityManager; 


    @Autowired 
    EntityManagerFactory entityManagerFactory; 

    @Autowired 
    CustomerRepository customerRepository; 

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class); 

    /** 
    * Simply selects the home view to render by returning its name. 
    * @throws Exception 
    */ 
    @Transactional 
    @RequestMapping(value = "/", method = RequestMethod.GET) 
    public String home(Locale locale, Model model) { 
     logger.info("Welcome home controller! The client locale is {}.", locale); 

     Customer c = new Customer("Rishi", "Paranjape"); 
     customerRepository.save(c); 

      //Following 4 lines work just fine. Database row is actually created. 
     //EntityManager em = entityManagerFactory.createEntityManager(); 
     //em.getTransaction().begin(); 
     //em.persist(c); 
     //em.getTransaction().commit(); 

     Date date = new Date(); 
     DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); 

     String formattedDate = dateFormat.format(date); 

     model.addAttribute("serverTime", formattedDate); 
     //throw new Exception("bad stuff"); 
     return "home"; 
    } 

} 

我的servlet上下文的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" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 

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

    <!-- Enables the Spring MVC @Controller programming model --> 
    <annotation-driven /> 

    <!-- 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> 

    <context:component-scan base-package="com.rishi.app" /> 


    <beans:bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <beans:property name="dataSource" ref="dataSource" /> 
     <beans:property name="packagesToScan" value="com.rishi.app.models" /> 
     <beans:property name="jpaVendorAdapter"> 
     <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
     </beans:property> 
     <beans:property name="jpaProperties"> 
     <beans:props> 
      <beans:prop key="hibernate.hbm2ddl.auto">validate</beans:prop> 
      <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</beans:prop> 
     </beans:props> 
     </beans:property> 
    </beans:bean> 

    <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
     <beans:property name="url" value="jdbc:mysql://localhost:3306/spring" /> 
     <beans:property name="username" value="rishi" /> 
     <beans:property name="password" value="password" /> 
    </beans:bean> 

    <beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <beans:property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </beans:bean> 
    <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" /> 


</beans:beans> 

我有根上下文和servlet上下文。我所有的bean都在servlet上下文中(我的根上下文幾乎是空的)。我的主要問題是em.persist()被調用,但什麼都不做。如果我調試應用程序,我可以看到被稱爲CustomerRepository的保存方法。沒有任何異常拋出或顯示任何錯誤。但是,沒有創建數據庫行。

+0

你可以發佈你的web.xml嗎? –

+0

好的類,但我想你也陷入了重複組件掃描的陷阱,這會導致你的'CustomerRepository'的代理和非代理實例都基本上呈現所有的AOP(包括事務)無用。 –

+0

用你的根和servlet上下文配置文件,我們都猜測。請張貼他們。 – MarkOfHall

回答

5

可能的原因是@Transactional正在錯誤的spring環境中應用於bean。

許多Spring MVC應用程序有兩個上下文:一個通常用於通用Bean的根上下文,如事務服務/存儲庫,以及一個包含控制器的Web特定上下文,更多詳細信息請參見此answer

似乎正在發生的事情是tx:annotation-driven正在應用於控制器或存儲庫都不存在的上下文中。

它看起來像@Transactional應用於根上下文,並將所有的bean放入調度程序上下文中。

如果是這種情況,請將tx:annotation-driven移動到定義bean的XML文件或相應的component-scan。這將適用@Transactional在豆是肯定的上下文。

通常作爲一般的最佳實踐,我們申請@Transactional不能在控制器上,並沒有對資源庫,但在中間業務層與豆@Service annotatted,其中包含業務邏輯。

但是版本庫和控制器只是春豆,所以如果你想使用@transactional也可以。

+0

我有根上下文和servlet上下文。我所有的bean都在servlet上下文中(我的根上下文幾乎是空的)。我的主要問題是調用em.persist()。如果我調試應用程序,我可以看到被稱爲CustomerRepository的保存方法。沒有任何異常拋出或顯示任何錯誤。但是,沒有創建數據庫行。 – riship89

+0

如果tx:annotation-driven僅在根上下文中,那麼這將解釋爲什麼servlet上下文中的bean不是事務性的。嘗試在servlet上下文中添加tx:annotation-driven。否則,如果您發佈servlet上下文xml和根上下文xml,這將有助於查明解決方案。 –

+0

不,你沒有得到我。驅動的tx註釋在servlet上下文中不在根上下文中。 – riship89

2

首先爲您的存儲庫編寫集成測試。縮小問題是否存在於控制器或存儲庫中會更容易。

從理論上講,你@Transactionalsave()方法是在界面上沒有,所以JDK動態代理不會爲它,除非你添加proxy-target-class=true<tx:annotation-driven>元素,並添加CGLIB到類路徑中創建的。如果沒有創建代理,則沒有建議來執行交易工作。您可以通過在存儲庫中設置斷點並查看堆棧幀來查看是否有任何類型的TransactionInterceptor類。在實踐中,如果事務代理丟失,我希望得到一個異常,你沒有打開會話(至少在Hibernate中)。由於你沒有得到異常,我懷疑Spring正在裝飾你的控制器的@Transactional,這不是一個交易問題。

要測試它是否爲事務性問題,請在保存後調用flush(),在flush之後但事務關閉之前放置斷點,並在其他位置(集成測試,數據庫控制檯,其他任何位置)創建新事務與READ_UNCOMMITTED隔離,並檢查是否可以髒讀(請參閱)該行。

0

刪除mode=aspectj,因爲沒有JVM代理和<context:load-time-weaver/>(也請參閱此answer),此功能無法正常工作。

刪除這將允許Spring使用非aspectj編織機制(JDK代理或CGLIB代理(如果適用)),因此@Transactional應該在servlet上下文中使用任何bean。

+0

這並不完全正確,aspectj模式也適用於編譯時編織。 –

4

您正在使用javax.transaction.Transactional,而您應該真的使用org.springframework.transaction.annotation.Transactional