【问题标题】:Spring Data with JPA not rolling back transaction on error带有 JPA 的 Spring Data 不会在错误时回滚事务
【发布时间】:2017-12-15 18:48:02
【问题描述】:

我们为 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 是否存在任何事务回滚问题?

【问题讨论】:

  • 为了澄清,您使用的是org.springframework.transaction.annotation.Transactional 还是javax.transaction.Transactional?而insertEvent()是过程中第一个注解为Transactional的方法?
  • 事务注解是org.springframework.transaction.annotation.Transactional。是的,insertEvent 方法使用@Transactional 注释,如上所示。
  • 什么是数据库?案例 MySQL:没有 engine=InnoDB 就不可能回滚
  • PostgreSQL。事实上,即使我尝试删除,Spring Data 也会抱怨没有事务:javax.persistence.TransactionRequiredException: Executing an update/delete query。所以没有找到交易,即使我注释了它!

标签: spring jpa spring-data spring-data-jpa


【解决方案1】:

信不信由你,我们修复了它。解决方案分为两部分:

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

【讨论】:

  • 这可能有点晚,但只是为了分享。我有同样的问题,我失败的唯一原因是我必须为 @Transactional 添加 rollBackFor = Exception.class 我将包路径添加到 setPackagesToScan 并删除它得到了相同的结果。
【解决方案2】:

您必须在JpaConfig 类中添加@EnableTransactionManagement 注释才能启用Spring 的注释驱动事务管理功能。

【讨论】:

  • 好建议,我补充说,但交易仍然没有回滚。我看到在第 2 部分中的错误之后,第 1 部分被保留,在相同的跨服务方法中。
  • 我们修复了它——我回答了这个问题。感谢您的帮助
猜你喜欢
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
  • 2014-12-11
  • 2018-05-24
  • 2015-05-04
相关资源
最近更新 更多