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
Come si fa a diagnosticare che le transazioni "non funzionano"? –
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. –
Abilita i logger "org.springframework.transaction". Restituisce lo stesso. Questo aiuterà in ulteriori analisi. –