Spring @Transactional 不会回滚已检查的异常 [英] Spring @Transactional does not rollback checked exceptions
问题描述
当使用 @Transactional(rollbackFor)
抛出已检查的异常时,我一直坚持让 Spring 回滚事务.这是我的代码:
I have been stuck for a while to make Spring rollback a transaction when a checked exception is thrown using @Transactional(rollbackFor)
. Here is my code:
数据访问类:
@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
只是一个简单的检查异常:
Where CheckedException
is just a simple checked exception:
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());
}
}
最后,这是我的主要课程:
And finally, here is my main class:
@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();
}
}
我已经阅读了许多与这些问题相关的答案,所有答案都建议从代理本身外部调用事务方法,我就是这样做的.无论如何,实体总是在数据库中持久化,事务不会回滚.
I've read many answers related to these questions, all of them suggesting to call the transactional method from outside the proxy itself, which I did. Regardless, the entity is always persisted in the database anyway and the transaction is not rolled back.
任何帮助将不胜感激.
更新: 根据@kavithakaran-kanapathippillai 的回答,我调试了 TransactionAspectSupport.completeTransactionAfterThrowing()
方法,以及以下方法,发现回滚逻辑被执行.尽管如此,当查询数据库时实体仍然出现.因此,我启用了数据库日志记录以查看运行了哪些查询,我发现了以下内容:
UPDATE: As per @kavithakaran-kanapathippillai answer, I debugged the TransactionAspectSupport.completeTransactionAfterThrowing()
method, and the following methods as well, and found that the rollback logic is executed. The entity still appears when querieng the db though.
So, I enabled db logging to see what queries are run, and I found the following:
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 回滚工作正常.
I don't know why this happens but it looks like the Spring rollback is working fine.
UPDATE2: 问题是由于我的表使用的是 MyISAM 引擎(非事务引擎).一旦我将其更改为 InnoDB(事务引擎),该记录就不再持久化了.
UPDATE2: The problem was due to my table was using the MyISAM engine (non-transactional engine). Once I changed it to InnoDB (a transactional engine), the record is not persisted anymore.
推荐答案
下面这个方法就是spring在抛出异常时检查是否回滚的地方.类名是 TransactionAspectSupport
.您可以设置一个断点并查看 txInfo.transactionAttribute.rollbackOn(ex)
是否评估为 true
The following method is where spring checks whether to rollback when an exception is thrown. Class name is TransactionAspectSupport
. You can put a break point and see whether txInfo.transactionAttribute.rollbackOn(ex)
is evaluating to true
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo,
Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
.....
if (txInfo.transactionAttribute != null &&
txInfo.transactionAttribute.rollbackOn(ex)) {
参考:
这篇关于Spring @Transactional 不会回滚已检查的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!