2012-05-17 21 views
5

Tengo un pequeño problema con las transacciones. Uso Spring 3.1.1.RELEASE, Spring Data 1.0.3.RELEASE JPA con el proveedor de Hibernate. Cuando comienzo una prueba junit donde hay un método anotado con @Transactional, parece correcto, pero cuando comienzo una aplicación completa no hay errores, pero las transacciones no funcionan. Aquí está mi configuraciones y código de ejemplo:Spring, las transacciones JPA solo funcionan en la prueba JUnit pero no en la aplicación

applicationContext.xml

<context:annotation-config /> 
    <context:component-scan base-package="com.sheedo.upload" /> 
    <jpa:repositories base-package="com.sheedo.upload.repository" /> 
    <tx:annotation-driven transaction-manager="transactionManager" /> 

    <bean 
     class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
     <property name="locations"> 
      <list> 
       <value>classpath*:messages/*.properties</value> 
       <value>classpath*:*.properties</value> 
      </list> 
     </property> 
    </bean> 

    <bean id="entityManagerFactory" 
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="persistenceUnit" /> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 

    <bean id="dataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"> 
     <property name="url" value="${jdbc.url}" /> 
     <property name="user" value="${jdbc.username}" /> 
     <property name="password" value="${jdbc.password}" /> 
    </bean> 

persistence.xml

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <properties> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" /> 
     <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" /> 
     <property name="hibernate.show_sql" value="true" /> 
    </properties> 
</persistence-unit> 

UserRepository.java

Interfa pública UserRepository ce extiende CrudRepository < usuario, Long> {}

UserServiceImpl.java

@Service("userService") 
public class UserServiceImpl implements UserService { 

    @Autowired 
    private UserRepository userRepository; 

    @Override 
    @Transactional 
    public void addUser(String name, String surname) { 
     User u = new User(name, surname); 
     userRepository.save(u); 
     throw new RuntimeException(); // to invoke a rollback 
    } 
} 

UserServiceTest.java

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:/META-INF/spring/root-context.xml" }) 
public class UserServiceTest { 

    Logger log = LoggerFactory.getLogger(getClass()); 

    @Autowired 
    private UserService userService; 

    @Test 
    public void testUserAdd() { 
     userService.addUser("John", "Doe"); 
    } 

} 

En este caso de prueba unitaria, la transacción no funciona evento aunque el método de servicio está anotado con @Transactional. Cuando agrego a esta anotación testUserAdd() método consigo esto en la consola:

2012-05-17 11:17:54,208 INFO [org.springframework.test.context.transaction.TransactionalTestExecutionListener] - Rolled back transaction after test execution for test context [[[email protected] testClass = UserRepositoryTest, testInstance = [email protected], testMethod = [email protected], testException = java.lang.RuntimeException, mergedContextConfiguration = [[email protected] testClass = UserRepositoryTest, locations = '{classpath:/META-INF/spring/root-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]] 

lo cual es correcto, supongo. Entonces, ¿cómo es posible que la anotación @Transactional solo funcione en la clase de prueba de Junit, pero no en otras de primavera?

Mi teoría es que SpringJUnit4ClassRunner de alguna manera proporciona esta transacción. ¿Tengo algo mal en mi configuración de primavera que las transacciones no funcionan en mi aplicación, pero solo en las clases de prueba de Junit? ¿Algo falta en appContext?

Editar: registro:

2012-05-17 12:46:10,770 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 
2012-05-17 12:46:10,770 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Opened new EntityManager [[email protected]] for JPA transaction 
2012-05-17 12:46:10,979 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Not exposing JPA transaction [[email protected]] as JDBC transaction because JpaDialect [[email protected]] does not support JDBC Connection retrieval 
Hibernate: insert into user (name, surname) values (?, ?) 
2012-05-17 12:46:11,062 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Initiating transaction commit 
2012-05-17 12:46:11,062 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Committing JPA transaction on EntityManager [[email protected]] 
2012-05-17 12:46:11,142 DEBUG [org.springframework.orm.jpa.JpaTransactionManager] - Closing JPA EntityManager [[email protected]] after transaction 
2012-05-17 12:46:11,142 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils] - Closing JPA EntityManager 
+0

¿Cómo se diagnostica que las transacciones "no funcionan"? –

+0

Cuando depuro este método transaccional en UserService, guardé la entidad en la base de datos después de "userRepository.save (user)" aunque el método finalizó con la excepción. Y no tengo ninguna consola de inicio de sesión que comenzó la transacción. –

+0

Active los registradores "org.springframework.transaction". Realice el mismo proceso. Esto ayudará en un análisis posterior. –

Respuesta

2

que tenían exactamente el mismo problema. Además, lea la solución de agregar una etiqueta <tx:annotation-driven/> en mi configuración web (spring-servlet.xml, en lugar de applicationContext.xml), y funcionó para mí.

Pero yo no considero que una buena solución, así que traté de entender por qué lo que estaba ocurriendo ...

Y así, resultó que una etiqueta <context:component-scan> que tenía en mi spring-servlet.xml también fue incluida la @Service clases en su escaneo (la especificación base-package era demasiado general). Esto fue extraño porque tenía un include-filter en el lugar que se refiere a la anotación @Controller ... pero de todos modos, parece que el contexto de la aplicación para la capa web fue el que creó las instancias @Service en lugar del contexto de la aplicación creado para applicationContext.xml --que es el que define la capa empresarial, y como el primero no tenía habilitada la transaccionalidad ... no tenía ninguna transacción.

Solución (buena): mejor (más específico) component-scan configuración en spring-servlet.xml

+0

Tenía el mismo problema. El contexto de la aplicación web estaba cargando beans incorrectos a pesar de que se hayan definido filtros de inclusión. Y obviamente no había en el contexto de la aplicación web. Inspeccione sus registros para ver cuándo spring-servlet.xml (o lo que usted denominó su aplicación web layercontext) carga y busca esta declaración en el registro: "Bean factory for WebApplicationContext" - puede buscar entre los beans para ver si la aplicación web contexto cargado. –

Cuestiones relacionadas