5

Mam mały problem z transakcjami. Używam Spring 3.1.1.RELEASE, Spring Data 1.0.3.RELEASE JPA z dostawcą Hibernate. Po uruchomieniu testu junit, gdzie jest metoda opisana za pomocą @Transactional, wydaje się to być w porządku, ale kiedy rozpoczynam całą aplikację, nie ma błędów, ale transakcje nie działają. Oto moje konfiguracje i przykładowy kod:Wiosna, transakcje JPA działają tylko w teście JUnit, ale nie w aplikacji

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 publicznego ce UserRepository rozciąga CrudRepository < Użytkownika, 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"); 
    } 

} 

W tym przypadku testu JUnit, transakcja nie działa imprezę chociaż metoda serwisowa jest opatrzona przypisami z @Transactional. Kiedy dodać adnotację do testUserAdd() metodą uzyskać to w konsoli:

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

która jest poprawna przypuszczam. Więc, jak to możliwe, że adnotacja @Transactional działa tylko w klasie testowej Junit, ale nie w innych komponentach sprężynowych?

Moja teoria mówi, że w pewnym sensie zapewnia ona tę transakcję. Czy mam coś nie tak w mojej konfiguracji wiosennej, że transakcje nie działają w mojej aplikacji, ale tylko w klasach testowych Junit? Coś brakuje w appContext?

Edit: dziennika:

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

Jak zdiagnozować, że transakcje „nie działa”? –

+0

Po debugowaniu tej metody transakcyjnej w usłudze UserService, obiekt został zapisany w bazie danych po "userRepository.save (user)", mimo że metoda zakończyła się wyjątkiem. I nie mam konsoli logowania, która rozpoczęła się. –

+0

Włącz rejestratory "org.springframework.transaction". Ustaw to samo. Pomoże to w dalszej analizie. –

Odpowiedz

2

miałem dokładnie ten sam problem. Zapoznaj się także z rozwiązaniem dodawania znacznika <tx:annotation-driven/> w mojej konfiguracji internetowej (spring-servlet.xml, zamiast applicationContext.xml) i działa dla mnie.

Ale nie uważają, że to dobre rozwiązanie, więc starałem się zrozumieć, dlaczego tak się dzieje ...

I dobrze, okazało się, że <context:component-scan> tag miałem w moim spring-servlet.xml również tym @Service klasy w swoim skanowaniu (specyfikacja base-package była zbyt ogólna). To było dziwne, ponieważ miałem include-filter w miejscu odnoszące się do adnotacji @Controller ... ale w każdym razie wydaje się, że kontekst aplikacji dla warstwy internetowej był tym, który tworzy instancje @Service zamiast kontekstu aplikacji utworzonego dla applicationContext.xml - który jest ten, który definiuje warstwę biznesową - i jako że poprzednia nie miała włączonej transakcji ... Nie miałem żadnych transakcji.

Solution (dobry): lepsze (bardziej konkretny) component-scan konfiguracja na spring-servlet.xml

+0

Miał ten sam problem. Kontekst aplikacji internetowej ładował nieprawidłowe ziarna, mimo że zdefiniowano filtry filtrów. I oczywiście nie było w kontekście aplikacji internetowej. Sprawdź dzienniki, aby sprawdzić, czy plik spring-servlet.xml (lub jakkolwiek nazwałeś swój applicationcontext warstwy sieciowej) wczytuje to stwierdzenie w dzienniku: "Fabryka fasoli dla WebApplicationContext" - możesz przeszukiwać te ziarna, aby sprawdzić, czy aplikacja internetowa kontekst załadował go. –

Powiązane problemy