2014-01-29 5 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"; 
    } 

} 

Мой сервлет контекст 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> 

У меня есть корневой контекст и контекст сервлета. Мои бобы находятся в контексте сервлета (мой корневой контекст почти пуст). Моя основная проблема - вызов em.persist(), но ничего не делает. Если я отлаживаю приложение, я вижу способ сохранения из вызываемого CustomerRepository. Никаких исключений и ошибок не было показано. Но, тем не менее, ни одна строка базы данных не создается.

+0

Не могли бы вы также опубликовать свой web.xml? –

+0

Хорошие классы, но я думаю, вы также попали в ловушку дублирования компонентного сканирования, что приводит к прокси-и непроксированным экземплярам вашего «CustomerRepository», который в основном делает все ваши AOP (включая транзакции) бесполезными. –

+0

Без конфигурационных файлов контекста корня и сервлета мы все догадываемся. Пожалуйста, опубликуйте их. – MarkOfHall

ответ

5

Вероятная причина в том, что @Transactional применяется к фасоли в неправильном контексте пружины.

Многие приложения Spring MVC имеют два контекста: один корневой контекст, обычно используемый для общих компонентов, таких как транзакционные службы/репозитории, и веб-контекст, содержащий среди прочих контроллеры, см. Это answer для получения дополнительной информации.

Что похоже на то, что tx:annotation-driven применяется к контексту, где не существует ни контроллера, ни хранилища.

Похоже, @Transactional применяется к корневому контексту и помещает все компоненты в контекст диспетчера.

Если это так, переместите tx:annotation-driven в файлы XML, в которых определены бобы, или соответствующие component-scan. Это применит @Transactional в контексте, где фасоли наверняка.

Обычно, как правило, мы применяем @Transactional не на контроллере, ни на репозитории, а на промежуточном бланке сервиса, аннотированном @Service, который содержит бизнес-логику.

Но репозитории и контроллеры - это просто фасоль, поэтому, если вы хотите использовать @transactional, который тоже работает.

+0

У меня есть контекст корня и контекст сервлета. Мои бобы находятся в контексте сервлета (мой корневой контекст почти пуст). Моя главная проблема - вызов em.persist(). Если я отлаживаю приложение, я вижу способ сохранения из вызываемого CustomerRepository. Никаких исключений и ошибок не было показано. Но, тем не менее, ни одна строка базы данных не создается. – riship89

+0

Если tx: annotation-driven находится только в корневом контексте, это объясняет, почему beans в контексте сервлета не являются транзакционными. Попробуйте добавить tx: annotation-driven в контексте сервлета. В противном случае, если вы разместите xml-контекст сервлета и корневой контекст xml, это поможет определить решение. –

+0

Нет, ты меня не достал. tx-аннотация управляется в контексте сервлета не в корневом контексте. – riship89

2

Начните с написания теста интеграции только для своего репозитория. Будет проще сузить вопрос, находится ли проблема в вашем контроллере или репозитории.

В теории, ваш @Transactional хранилище save() метод не в интерфейсе, так что JDK динамического прокси не будет создан для этого, если вы не добавите proxy-target-class=true к вашему <tx:annotation-driven> элемент и добавить CGLIB к вашему пути к классам. Если прокси-сервер не создан, нет никаких рекомендаций для выполнения транзакционной работы. Вы можете проверить это, установив точку останова в репозитории и посмотрев на фреймы стека, чтобы узнать, есть ли упоминание о классе TransactionInterceptor.

На практике, если прокси-сервер транзакции отсутствует, я ожидаю получить исключение, если у вас нет открытого сеанса (по крайней мере, в спящем режиме). Поскольку вы не получаете исключения, я подозреваю, что Spring украшает ваш контроллер @Transactional и что это не транзакция.

Чтобы проверить, является ли транзакционная проблема, позвоните по номеру flush() после сохранения, поставьте точку останова после флеша, но перед закрытием транзакции и в другом месте (интеграционный тест, консоль БД, что угодно) создайте новую транзакцию с изоляцией READ_UNCOMMITTED и проверьте, можете ли вы грязно прочитать (см.) строку.

0

Удалить mode=aspectj, так как это не работает без агента JVM и <context:load-time-weaver/> (см. Также этот answer).

Удаление этого параметра позволит Spring использовать механизм неаспектного ткачества (прокси JDK или прокси CGLIB, если применимо), поэтому @Transactional должен затем работать с любыми компонентами в контексте сервлета.

+0

Это не совсем так, режим aspectj работает и во время компиляции. –

4

Вы используете javax.transaction.Transactional, в то время как вы действительно должны использовать org.springframework.transaction.annotation.Transactional.

 Смежные вопросы

  • Нет связанных вопросов^_^