Spring Boot多类DB操作@Transactional事务不统一回滚问题求助
问题描述
希望将多个类中的数据库调用纳入同一事务,预期当任意查询(学生、教师相关)抛出CustomException时,所有数据库操作均回滚。但测试发现,若TeacherHandler中出现异常,仅TeacherDao的查询回滚,StudentDao的查询未回滚。
示例代码
父类(服务1)
@Service @Slf4j @RequiredArgsConstructor public class Processor { private final StudentHandler studentHandler; private final TeacherHandler teacherHandler; @Transactional(rollbackFor = {CustomException.class}) public void execute(MessageObj msg) { //调用处理器1 studentHandler.process(msg); //调用处理器2 teacherHandler.process(msg); } }
处理器类1(StudentHandler)
@Service @Slf4j @RequiredArgsConstructor public class StudentHandler { private final StudentDao studentDao; @Transactional(rollbackFor = {CustomException.class}) public void process(MessageObj obj){ studentDao.saveStudent(obj); } }
处理器类2(TeacherHandler)
@Service @Slf4j @RequiredArgsConstructor public class TeacherHandler { private final TeacherDao teacherDao; @Transactional(rollbackFor = {CustomException.class}) public void process(MessageObj obj){ teacherDao.saveTeacher(obj); } }
Student Dao类
@Repository @RequiredArgsConstructor @Slf4j public class StudentDao { private final JdbcTemplate jdbcTemplate; @Transactional(rollbackFor = {CustomException.class}) public void saveStudent(MessageObj obj){ jdbcTemplate.save("student_query",obj); jdbcTemplate.save("audit_query",obj); } }
Teacher Dao类
@Repository @RequiredArgsConstructor @Slf4j public class TeacherDao { private final JdbcTemplate jdbcTemplate; @Transactional(rollbackFor = {CustomException.class}) public void saveTeacher(MessageObj obj){ jdbcTemplate.save("student_query",obj); } }
解决方案
- 移除子方法的事务注解:只保留最外层
Processor.execute()方法上的@Transactional(rollbackFor = {CustomException.class}),删除StudentHandler.process()、TeacherHandler.process()、StudentDao.saveStudent()、TeacherDao.saveTeacher()上的所有@Transactional注解。这样所有数据库操作都会纳入最外层的同一个事务中,任意环节抛出CustomException都会触发整体回滚。 - 确保异常正常传递:检查所有中间方法(如
TeacherHandler.process())是否捕获了CustomException并未向上抛出。必须保证异常能传递到最外层的execute()方法,否则外层事务无法感知异常,不会触发回滚。 - 显式指定事务传播行为(可选):如果必须保留子方法的事务注解,需显式设置传播属性为
Propagation.REQUIRED(默认值,可省略),确保子方法加入外层事务而非创建新事务。例如:@Transactional(rollbackFor = {CustomException.class}, propagation = Propagation.REQUIRED)。
内容的提问来源于stack exchange,提问作者karthik bulusu
相关产品推荐
相关产品推荐

