You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:01:09