2010-10-29 6 views
12

J'essaie d'obtenir une annulation de transaction JDBC lors de l'utilisation de Spring-test sans succès. Lorsque je lance ce qui suit, la mise à jour SQL est toujours validée.Annulation de transaction sur les tests Spring JDBC

package my.dao.impl; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.test.annotation.Rollback; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.TestExecutionListeners; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 
import org.springframework.test.context.transaction.TransactionConfiguration; 

import javax.sql.DataSource; 
import java.sql.Connection; 
import java.sql.Statement; 

@RunWith(SpringJUnit4ClassRunner.class) 
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class}) 
@ContextConfiguration(locations={"classpath:ApplicationContext-test-DAOs.xml"}) 
@TransactionConfiguration(defaultRollback = true) 
public class ConfirmationMatchingDAOImplTest { 

    @Autowired 
    private DataSource dataSource; 

    @Test 
    public void shouldInsertSomething() throws Exception { 
     final Connection connection = dataSource.getConnection(); 
     final Statement statement = connection.createStatement(); 
     statement.executeUpdate("insert into TEST_INSERT values (1, 'hello')"); 
     statement.close(); 
     connection.close(); 
    } 
} 

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> 
    <property name="url" value="jdbc:sqlserver://makeitfunky:1490;databaseName=fonzie"/> 
    <property name="username" value="ralph"/> 
    <property name="password" value="p0n1es_R_kew1"/> 
</bean> 

Qu'est-ce que je fais mal?

De plus, est-ce que j'utilise trop d'annotations? Puis-je le rendre un peu plus propre?

Répondre

16

Si vous ne configurez pas explicitement les auditeurs d'exécution des tests en utilisant l'annotation @TestExecutionListeners, Spring par défaut configure DependencyInjectionTestExecutionListener, DirtiesContextTestExecutionListener et TransactionalTestExecutionListener. TransactionalTestExecutionListener fournit une exécution de test transactionnelle avec la sémantique d'annulation par défaut. En déclarant explicitement @TestExecutionListeners sur votre classe de test et en omettant TransactionalTestExecutionListener de la liste des écouteurs, vous désactivez le support transactionnel.

Vous devez également ajouter l'annotation @Transactional au niveau de la classe ou de la méthode.

Vous devez également utiliser DataSourceUtils pour obtenir une connexion transactionnelle gérée par DataSourceTransactionManager.

+0

J'ai supprimé @TestExecutionListeners et ajouté @Transactional. J'ai ensuite dû ajouter un bean transactionManager au contexte de l'application (DataSourceTransactionManager). Txn n'a pas été restauré, j'ai donc ajouté @TransactionConfiguration (defaultRollback = true). Txn n'était toujours pas annulé et j'ai ajouté @Rollback à la méthode de test. C'est seulement à ce moment-là que j'ai vu le journal de Spring qu'il était en train de reculer le txn, mais la mise à jour est toujours conservée dans la base de données. Quelque chose à voir avec SQL Server et son pilote peut-être? – Synesso

+1

Ajout de DataSourceUtils à ma réponse. –

+0

Ah, je n'ai pas été averti de votre dernier commentaire. En attendant, j'ai changé mon contexte pour envelopper la source de données dans un TransactionAwareDataSourceProxy. Ça a marché. Alors voilà, deux façons de faire la même chose. Maintenant, pour voir laquelle de ces 7 annotations je peux me débarrasser de et continuer à faire fonctionner la chose. – Synesso

1

Est-ce parce que vous n'avez pas de @Transactional pour la méthode d'essai?

+1

J'ai ajouté @Transactional et cela n'a eu aucun effet. J'ai aussi ajouté @Rollback et cela n'avait toujours aucun effet. – Synesso

0

Lorsque vous utilisez l'@Transactional annotation au printemps, vous devez ajouter la ligne suivante dans votre fichier de configuration Spring:

<tx:annotation-driven transaction-manager="transactionManager"/> 

La propriété transaction gestionnaire contient une référence à la fève de gestionnaire de transactions défini dans le Fichier de configuration Spring. Ce code indique à Spring d'utiliser l'annotation @Transaction lors de l'application de l'intercepteur de transaction. Sans cela, l'annotation @Transactional est ignorée, ce qui signifie qu'aucune transaction n'est utilisée dans votre code.

Source on IBM website

+1

Je ne me souviens plus du problème, mais merci pour les infos supplémentaires. – Synesso

0

Informations supplémentaires:

pour cette ligne

<tx:annotation-driven transaction-manager="transactionManager"/> 

La valeur par défaut de l'attribut transaction-manager est "transactionManager". Cet attribut est obligatoire uniquement si l'identifiant/nom du bean transactionManager n'est pas 'transactionManager'. Donc vous venez de définir:

<tx:annotation-driven /> 
0

Vous devez ajouter @Transactional au niveau de la classe. Quelque chose comme ceci:

@TransactionConfiguration(transactionManager = "txManager",defaultRollback = true) 
@Transactional 

Voici txManager est un identifiant d'instance ou de haricot gestionnaire de transactions de application context.

<!-- Transaction Manager --> 
    <bean id="txManager" 
      class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory" /> 
    </bean> 

    <tx:annotation-driven transaction-manager="txManager" /> 
2

Si vous utilisez la méthode non-xml cela fonctionne bien depuis sur la version 3,1

@Transactional 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = {TestDbConfig.class, SomeService.class}) 
public class SomeTest { 

@Inject 
private SomeService someService; 

@PersistenceContext 
private EntityManager em; 

@Test 
public void someTest() {} 

La configuration de test prend alors cette forme. Notez @EnableTransactionManagement et le fait que vous pouvez déclarer un test global defaultRollback. Cela devient particulièrement utile sur un grand projet.

@Configuration 
@PropertySource(value = "classpath:app.properties") 
@EnableTransactionManagement 
@TransactionConfiguration(defaultRollback = true) 
public class TestDbConfig { 

//read the parameters from properties 
@Value("${hibernate.dialect:unset}") 
private String hibernateDialect; 

@Bean 
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() { 
    return new PropertySourcesPlaceholderConfigurer(); 
} 

@Bean 
public PlatformTransactionManager transactionManager() { 
    //for example 
    JpaTransactionManager transactionManager = new JpaTransactionManager(); 
    transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); 
    return transactionManager; 
} 

@Bean 
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { 
    //set the datasource 
    //set the JpaVendorAdapter 
    //set the packagesToScan 
    return some sort of LocalContainerEntityManagerFactoryBean; 
} 

@Bean 
DataSource dataSource() { 
    return dataSource from jndi or a DriverManagerDataSource(); 
} 

}

2

ajouter cette annotation, et aucun rouleau arrière sera en cas de test:

@TransactionConfiguration(defaultRollback=false) 

Mon annotation ressemble à ceci:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "/../applicationContext.xml" }) 
@TransactionConfiguration(defaultRollback=true) 
public class DBCreatorTest { 
Questions connexes