使用JPA的Spring数据不会在出错时回滚事务

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用JPA的Spring数据不会在出错时回滚事务相关的知识,希望对你有一定的参考价值。

我们为JPA配置了Spring Data。服务事务方法不会因错误而回滚(例如,DB ConstraintViolationException)。

我能找到的最接近的是这个(Transaction not rolling back) Spring-data, JTA, JPA, Wildfly10,但是我们没有任何XML配置,我们所有的配置都是基于Java的。

从本质上讲,服务方法看起来像这样:没有错误被捕获,一切都被抛出。

@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);   
}

第2部分失败。但是在错误和返回之后,我看到事件(第1部分)仍然在数据库中填充。

我们还尝试了@Transactional的各种组合,没有任何效果:

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

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);
    }   

}

Spring Data和JPA是否存在任何事务回滚问题?

答案

您必须将@EnableTransactionManagement注释添加到JpaConfig类,以便启用Spring的注释驱动的事务管理功能。

另一答案

信不信由你,我们修复它。该解决方案有两个部分:

1)按照ledniov描述的那样将@EnableTransactionManagement添加到JpaConfig,但仅此一项是不够的;

2)同样在entityManagerFactory()的JpaConfig中,将Service类包添加到以下setPackagesToScan中。以前,域对象包在那里,但服务对象包不是。我们添加了"myapp.service",第二个包。

@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;
}

以上是关于使用JPA的Spring数据不会在出错时回滚事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring事务异常回滚,捕获异常不抛出就不会回滚

Spring Data:重试时回滚事务

Spring事务异常回滚,捕获异常不抛出就不会回滚

Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题

JPA中事务回滚的问题

外部事务失败时回滚内部事务