问题
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:
The data access class:
@Repository
public class CustomerDao {
@Autowired
private SessionFactory sessionFactory;
public void willRollback() throws CheckedException {
sessionFactory.getCurrentSession().persist(new SpringCustomer(null, "roll back"));
throw new CheckedException();
}
}
Where CheckedException
is just a simple checked exception:
public class CheckedException extends Exception {}
The service class CustomerService
:
@Service
public class CustomerService {
@Autowired
private CustomerDao customerDao;
@Transactional(transactionManager = "hibernateTransactionManager", rollbackFor = CheckedException.class)
public void willRollback() throws CheckedException {
customerDao.willRollback();
}
}
Beans configurations:
@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.
Any help would be appreciated.
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
I don't know why this happens but it looks like the Spring rollback is working fine.
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.
回答1:
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)) {
Reference:
TransactionAspectSupport.java
来源:https://stackoverflow.com/questions/62613814/spring-transactional-does-not-rollback-checked-exceptions