5

Ho un piccolo problema con le transazioni. Uso Spring 3.1.1.RELEASE, Spring Data 1.0.3.RELEASE JPA con il fornitore di Hibernate. Quando avvio un test junit in cui è annotato un metodo con @Transactional, sembra soddisfacente, ma quando avvio un'intera applicazione non ci sono errori ma le transazioni non funzionano. Ecco il mio configurazioni e codice di esempio:Spring, le transazioni JPA funzionano solo nel test JUnit ma non nell'applicazione

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 pubblico ce UserRepository estende CrudRepository < utente, 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"); 
    } 

} 

In questo caso di test JUnit, operazione non funziona evento sebbene il metodo di servizio sia annotato con @Transactional. Quando aggiungo questa annotazione a testUserAdd() metodo ottengo questo in console:

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']]] 

che è corretto suppongo. Quindi, come può essere possibile che l'annotazione @Transactional funzioni solo nella classe di test di Junit, ma non in altri bean di primavera?

La mia teoria è che SpringJUnit4ClassRunner fornisce in qualche modo questa transazione. Ho qualcosa di sbagliato nella mia configurazione di primavera che le transazioni non funzionano nella mia app ma solo nelle classi di test Junit? Qualcosa manca in appContext?

Edit: 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 [org.springframework.orm.jpa.Def[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

Come si fa a diagnosticare che le transazioni "non funzionano"? –

+0

Quando eseguo il debug di questo metodo transazionale in UserService, esso ha salvato l'entità nel database dopo "userRepository.save (utente)" anche se il metodo ha terminato con l'eccezione. E non ho il login nella console che la transazione abbia avuto inizio. –

+0

Abilita i logger "org.springframework.transaction". Restituisce lo stesso. Questo aiuterà in ulteriori analisi. –

risposta

2

Ho avuto esattamente lo stesso problema. Inoltre, leggi la soluzione di aggiungere un tag <tx:annotation-driven/> nella mia configurazione web (spring-servlet.xml, anziché applicationContext.xml) e ha funzionato per me.

Ma non ritengo che una buona soluzione, così ho cercato di capire perché quello che stava succedendo ...

E bene, si è scoperto che un tag <context:component-scan> ho avuto nella mia spring-servlet.xml era anche compresa la @Service classi nella sua scansione (la specifica base-package era troppo generica). Questo era strano perché avevo un include-filter in riferimento all'annotazione @Controller ... ma comunque, sembra che il contesto dell'applicazione per il livello web fosse quello che creava le istanze @Service invece del contesto dell'applicazione creato per applicationContext.xml - che è quello che definisce il livello aziendale--, e poiché il primo non ha abilitato la transazione ... Non ho avuto alcuna transazione.

Solution (buona): migliore (più specifico) component-scan configurazione a spring-servlet.xml

+0

Aveva lo stesso problema. Il contesto dell'app Web stava caricando fagioli errati anche se i filtri di inclusione erano stati definiti. E ovviamente non c'era nel contesto dell'app web. Ispeziona i tuoi registri quando il file spring-servlet.xml (o qualsiasi cosa tu abbia chiamato il tuo livello applicazione web layer) carica e cerca questa dichiarazione nel registro: "Bean factory per WebApplicationContext" - puoi cercare attraverso quei bean per vedere se l'app web contesto caricato. –

Problemi correlati