Jpa @Transactional不回滚

时间:2019-02-10 06:26:32

标签: java spring jpa transactional

更新:该表已设置为MyISAM而不是InnoDB,从而解决了该问题。

所以我有这个方法:

@Transactional()
@Override
public List<Order> findAll() {
    Order order = new Order();
    Order order1 = new Order();
    Order order2 = new Order();
    orderRepository.save(order);
    orderRepository.save(order1);
    orderRepository.save(order2);

    return orders;
}

当其中一个引发异常时,其他不回滚。我试图设置一些错误的数据类型以获取DataException,但是后来我意识到这可能是一个检查异常?所以我这样做了:

    order2.setDishesReady(5);
    if(order2.getDishesReady() == 5){
        throw new RuntimeException();
    }

仍然没有回滚。我也尝试过

@Transactional(propagation=Propagation.REQUIRED)
@Transactional(rollbackFor = Exception.class)

还有没有办法伪造这样的回滚?通过在方法中引发异常,如果没有,如何测试回滚?这是我的配置:

@Configuration
@EnableWebMvc
@EnableTransactionManagement
public class AppConfig {


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em
                = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("com.project.models");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }
    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/project");
        dataSource.setUsername( "root" );
        dataSource.setPassword( "1234" );
        return dataSource;
    }
    @Bean
    public PlatformTransactionManager transactionManager(
            EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        return transactionManager;
    }
    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty(
                "hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        return properties;
    }

使用日志中的某些内容进行更新:

Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:05 - Creating new EntityManager for shared EntityManager invocation
""2019-02-10 09:30:05 - Closing JPA EntityManager
""2019-02-10 09:30:06 - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
""2019-02-10 09:30:06 - Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1d1cfe4, org.springframework.security.web.context.SecurityContextPersistenceFilter@10745a02, org.springframework.security.web.header.HeaderWriterFilter@3d798e76, org.springframework.web.filter.CorsFilter@ba562e0, org.springframework.security.web.authentication.logout.LogoutFilter@13c90c06, com.vision.project.security.JwtAuthenticationTokenFilter@7c447c76, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@72715e61, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5611bba, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5a51336a, org.springframework.security.web.session.SessionManagementFilter@386e9fd8, org.springframework.security.web.access.ExceptionTranslationFilter@5403431a, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@58b8f9e3]
""2019-02-10 09:30:07 - Initializing ExecutorService 'taskScheduler'
""2019-02-10 09:30:07 - Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
""2019-02-10 09:30:07 - Tomcat started on port(s): 8080 (http) with context path ''
""2019-02-10 09:30:07 - Started ProjectApplication in 13.85 seconds (JVM running for 15.214)
""2019-02-10 09:31:09 - Initializing Spring DispatcherServlet 'dispatcherServlet'
""2019-02-10 09:31:09 - Initializing Servlet 'dispatcherServlet'
""2019-02-10 09:31:09 - Completed initialization in 16 ms
""2019-02-10 09:31:09 - Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
""2019-02-10 09:31:09 - Found thread-bound EntityManager [SessionImpl(1272634933<open>)] for JPA transaction
""2019-02-10 09:31:09 - Creating new transaction with name [com.vision.project.services.OrderServiceImpl.findAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.RuntimeException,-java.lang.Exception
""2019-02-10 09:31:09 - Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@7234e97]
""2019-02-10 09:31:09 - Found thread-bound EntityManager [SessionImpl(1272634933<open>)] for JPA transaction
""2019-02-10 09:31:09 - Participating in existing transaction
""2019-02-10 09:31:09 - Found thread-bound EntityManager [SessionImpl(1272634933<open>)] for JPA transaction
""2019-02-10 09:31:09 - Participating in existing transaction
""2019-02-10 09:31:09 - Initiating transaction rollback
""2019-02-10 09:31:09 - Rolling back JPA transaction on EntityManager [SessionImpl(1272634933<open>)]
""2019-02-10 09:31:09 - Not closing pre-bound JPA EntityManager after transaction
""2019-02-10 09:31:09 - Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
""2019-02-10 09:31:09 - Closing JPA EntityManager

4.4级,Java 8, 依赖项:

    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.springframework.boot:spring-boot-starter-security")
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile "org.springframework.boot:spring-boot-configuration-processor"
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.1.2.RELEASE'
    compile group: 'org.springframework', name: 'spring-jdbc', version: '5.0.8.RELEASE'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '1.2.5.RELEASE'
    compile group: 'org.springframework.security', name: 'spring-security-jwt', version: '1.0.2.RELEASE'

    compile group: 'org.hibernate', name: 'hibernate-core', version: '5.4.1.Final'
    compile group: 'org.hibernate', name: 'hibernate-gradle-plugin', version: '5.3.5.Final'

    compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.6.0'
    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.6'
    compile group: 'com.mchange', name: 'c3p0', version: '0.9.5.2'

2 个答案:

答案 0 :(得分:0)

我正在回答要跳过更新的人们的问题。所以一段时间后,我意识到这样的事情:

    orderRepository.save(order1);
    orderRepository.save(order2);
    Order order = orderRepository.save(order3);
    order.setDishesReady = 5;
    orderRepository.delete(order3);
    if(order3.getDishesReady() == 5){
        throw new RuntimeException();
    }

仅对删除操作进行回滚,对保存操作不进行回滚,经过更多研究,我发现我的表设置为MyISAM而不是InnoDB。 来自What's the difference between MyISAM and InnoDB?的更多有关该主题的信息:

  

如果您需要数据库来强制执行外键约束,或者您需要数据库来支持事务(即,由两个或多个DML操作进行的更改作为单个工作单元处理,则所有更改都已应用,或者所有更改已恢复),则您将选择InnoDB引擎,因为MyISAM引擎缺少这些功能。

答案 1 :(得分:-1)

@Transactional仅回退未检查异常的事务。对于检查的异常及其子类,它将提交数据。因此,尽管在这里引发了一个异常,但由于它是一个已检查的异常,因此Spring会忽略该异常并将数据提交到数据库中,从而导致系统不一致。

@Transactional(rollbackFor = Exception.class)

如果抛出Exception或其子类,请始终将其与@Transactional批注一起使用,以告诉Spring如果发生检查的异常,则回滚事务。