Rollback Checked Exception in Spring Transaction
How to handle checked exceptions in Spring transactions to ensure rollback behavior.

- hpyYh
- 2 min read

Spring Rollback Issue
normally, in Spring Boot, when dealing with databases, if an unchecked exception occurs, the application rolls back the transaction. Conversely, if a checked exception occurs, the transaction does not roll back. The most common unchecked exceptions are SQLException and IOException.
@Transactional
@Override
public UUID createNotice(NoticeCommand noticeCommand) throws IOException {
User creator = userReader.getUser(noticeCommand.getCreatorId());
Notice notice = noticeCommand.toEntity(creator);
noticeStore.store(notice);
throw new IOException("Timeout Exception Test");
}
for example, if an IOException occurs as above, it does not roll back. Spring assumes that users can sufficiently preprocess such exceptions. (mostly expected to obligatorily include try-catch) in most cases, it is common to handle it with try-catch at the function
However, Most people expect to handle all exceptions. There are several ways to solve this problem.
Manually Rollback (Recommended)
@Transactional
@Override
public UUID createNotice(NoticeCommand noticeCommand) {
User creator = userReader.getUser(noticeCommand.getCreatorId());
Notice notice = noticeCommand.toEntity(creator);
noticeStore.store(notice);
try {
throw new IOException("Timeout Exception Test");
}catch (IOException e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Transactional(rollbackFor = Exception.class)
developer add rollbackFor option to @Transactional annotation.
@Transactional(rollbackFor = Exception.class)
@Override
public UUID createNotice(NoticeCommand noticeCommand) {
User creator = userReader.getUser(noticeCommand.getCreatorId());
Notice notice = noticeCommand.toEntity(creator);
noticeStore.store(notice);
throw new IOException("Timeout Exception Test");
}
New annotation Create : NewTransactional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Transactional(rollbackFor = Exception.class)
public @interface NewTransactional {
@AliasFor(annotation = Transactional.class)
Propagation propagation() default Propagation.REQUIRED;
}
AOP, class shawding, annotation overriding …
@Transactional annotation automatically add Exception rollback rule.
@Configuration
public class TransactionConfig {
@Bean(name = "winiTransactionAttributeSource")
@Primary
public TransactionAttributeSource winiTransactionAttributeSource() {
return new AnnotationTransactionAttributeSource() {
@Override
protected TransactionAttribute findTransactionAttribute(Method method) {
return updateRollbackRule(super.findTransactionAttribute(method));
}
@Override
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return updateRollbackRule(super.findTransactionAttribute(clazz));
}
private TransactionAttribute updateRollbackRule(TransactionAttribute attr) {
if (attr instanceof RuleBasedTransactionAttribute) {
RuleBasedTransactionAttribute rbta = (RuleBasedTransactionAttribute) attr;
rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class));
}
return attr;
}
};
}
}
- tags :
- Spring