【问题标题】:Spring @Transactional does not rollback checked exceptionsSpring @Transactional 不回滚检查的异常
【发布时间】:2020-10-18 04:20:59
【问题描述】:

当使用@Transactional(rollbackFor) 引发检查的异常时,我一直坚持让 Spring 回滚事务。这是我的代码:

数据访问类:

@Repository
public class CustomerDao {

    @Autowired
    private SessionFactory sessionFactory;
    
    public void willRollback() throws CheckedException {
        sessionFactory.getCurrentSession().persist(new SpringCustomer(null, "roll back"));
        throw new CheckedException();
    }
}

CheckedException 只是一个简单的检查异常:

public class CheckedException extends Exception {}

服务类CustomerService

@Service
public class CustomerService {
    
    @Autowired
    private CustomerDao customerDao;
    
    @Transactional(transactionManager = "hibernateTransactionManager", rollbackFor = CheckedException.class)
    public void willRollback() throws CheckedException {
        customerDao.willRollback();
    }
}

Beans 配置:

@Configuration
public class BasicConfig {
    
    @Bean
    public DataSource dataSource() {

        DriverManagerDataSource ds = new DriverManagerDataSource();

        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/test_hibernate?useSSL=false");
        ds.setUsername("root");
        ds.setPassword("Passw0rd");

        return ds;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {

        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource());
        localSessionFactoryBean.setPackagesToScan("com.home.exception.checked");

        Properties hibernateProperties = new Properties();
        hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        hibernateProperties.put("hibernate.show_sql", "true");
        hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
        localSessionFactoryBean.setHibernateProperties(hibernateProperties);

        return localSessionFactoryBean;
    }

    @Bean
    public HibernateTransactionManager hibernateTransactionManager() {
        return new HibernateTransactionManager(sessionFactory().getObject());
    }

}

最后,这是我的主要课程:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class Main {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext ctx = 
                new AnnotationConfigApplicationContext(Main.class); 
        
        try {
            ctx.getBean(CustomerService.class).willRollback();
        } catch (CheckedException e) {
            e.printStackTrace();
        }
        
        ctx.close();
    }
}

我已经阅读了许多与这些问题相关的答案,所有答案都建议从代理本身外部调用事务方法,我这样做了。无论如何,实体总是被持久化在数据库中并且事务不会回滚。

任何帮助将不胜感激。


更新: 根据@kavithakaran-kanapathippillai 的回答,我调试了TransactionAspectSupport.completeTransactionAfterThrowing() 方法以及以下方法,发现执行了回滚逻辑。但是,当查询数据库时,实体仍然出现。 因此,我启用了 db logging 以查看正在运行的查询,我发现了以下内容:

2020-06-28T07:29:48.516038Z   391 Query SET autocommit=0
2020-06-28T07:29:48.520253Z   391 Query insert into spring_customer (name) values ('roll back')
2020-06-28T07:29:48.524969Z   391 Query rollback
2020-06-28T07:29:48.526026Z   391 Query SET autocommit=1

我不知道为什么会发生这种情况,但看起来 Spring 回滚工作正常。


UPDATE2:问题是由于我的表使用的是 MyISAM 引擎(非事务性引擎)。一旦我将其更改为 InnoDB(事务引擎),记录就不再持久化了。

【问题讨论】:

    标签: mysql transactions spring-data


    【解决方案1】:

    下面的方法是spring在抛出异常时检查是否回滚的地方。类名是TransactionAspectSupport。您可以设置一个断点并查看 txInfo.transactionAttribute.rollbackOn(ex) 是否正在评估为 true

    protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo,
                                                    Throwable ex) {
      if (txInfo != null && txInfo.getTransactionStatus() != null) {
         .....
        if (txInfo.transactionAttribute != null && 
            txInfo.transactionAttribute.rollbackOn(ex)) {
    
    

    参考:

    TransactionAspectSupport.java

    【讨论】:

    • 感谢您的提示。我已经用新发现更新了问题。
    • 你有没有直接在mysql中尝试过同样的操作序列?如果他们不回滚,可能值得用您的表定义提出一个单独的问题并将链接也保留在这里
    • 谢谢兄弟。问题是由于使用了 MyISAM 引擎。
    猜你喜欢
    • 2019-06-30
    • 2015-02-12
    • 2018-12-24
    • 1970-01-01
    • 2017-12-07
    • 2017-04-14
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    相关资源
    最近更新 更多