4 votes

Spring Data avec JPA n'annule pas la transaction en cas d'erreur

Nous avons configuré Spring Data pour JPA. Une méthode de transaction de service n'est pas annulée en cas d'erreur (par exemple, une DB ConstraintViolationException).

Le plus proche que j'ai pu trouver était ceci (Transaction not rolling back) Spring-data, JTA, JPA, Wildfly10 mais nous n'avons pas de configuration XML, toute notre configuration est basée sur Java.

Essentiellement, une méthode de service ressemble à ceci : aucune erreur n'est détectée, tout est lancé.

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
public void insertEvent() throws Exception {
     // Part 1
     EventsT event = new EventsT(); 
     // populate it..
     eventsDAO.save(event);

     // Part 2 - ERROR HAPPENS HERE (Constraint Violation Exception)
     AnswersT answer = new AnswersT();
     // populate it..
     answersDAO.save(answer);   
}

La partie 2 échoue. Mais après l'erreur et le retour, je vois que l'événement (partie 1) est toujours alimenté dans la base de données.

Nous avons également essayé diverses combinaisons de @Transactional, mais rien n'a fonctionné :

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = false)
@Transactional(readOnly = false)
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = ConstraintViolationException.class, readOnly = false)

Interfaces Spring Data CRUD DAO :

@Repository
public interface EventsDAO extends JpaRepository<EventsT, Integer> {

}

@Repository
public interface AnswersDAO extends JpaRepository<AnswersT, Integer> {

}

JpaConfig :

@Configuration
@EnableJpaRepositories(basePackages = "com.myapp.dao")
@PropertySource({ "file:${conf.dir}/myapp/db-connection.properties" })
public class JpaConfig {

    @Value("${jdbc.datasource}")
    private String dataSourceName;

    @Bean
    public Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<String, Object>();
        props.put("hibernate.dialect", PostgreSQL95Dialect.class.getName());
        //props.put("hibernate.cache.provider_class", HashtableCacheProvider.class.getName());
        return props;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setShowSql(true);
        hibernateJpaVendorAdapter.setGenerateDdl(true);
        hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws NamingException {
        return new JpaTransactionManager( entityManagerFactory().getObject() );
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(dataSource());
        lef.setJpaPropertyMap(this.jpaProperties());
        lef.setJpaVendorAdapter(this.jpaVendorAdapter());
        lef.setPackagesToScan("com.myapp.domain", "com.myapp.dao");
        return lef;
    }

    @Bean
    public DataSource dataSource() throws NamingException {
        return (DataSource) new JndiTemplate().lookup(dataSourceName);
    }   

}

Y a-t-il eu des problèmes de retour en arrière des transactions avec Spring Data et JPA ?

4voto

gene b. Points 1533

Croyez-le ou non, nous l'avons réparé. Il y avait 2 parties à la solution :

1) Ajouter @EnableTransactionManagement à JpaConfig comme ledniov l'a décrit, mais cela n'était pas suffisant ;

2) Toujours dans JpaConfig, dans entityManagerFactory() , ajoutez le Service au paquet de classes suivant setPackagesToScan . Auparavant, le paquet d'objets de domaine était présent, mais pas le paquet d'objets de service. Nous avons ajouté "myapp.service" le 2ème paquet.

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
    LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
    lef.setDataSource(dataSource());
    lef.setJpaPropertyMap(this.jpaProperties());
    lef.setJpaVendorAdapter(this.jpaVendorAdapter());
    lef.setPackagesToScan("myapp.domain", "myapp.service"); //NOTE: Service was missing
    return lef;
}

2voto

ledniov Points 1438

Vous devez ajouter @EnableTransactionManagement à l'annotation JpaConfig afin d'activer la capacité de gestion des transactions basée sur les annotations de Spring.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X