@Transactional注解回滚失效求助:JobOffer无法回滚
问题原因及解决方案
核心问题
你的@Transactional不生效的关键原因是Spring声明式事务基于动态代理实现,同一个类内部的方法调用不会触发代理逻辑。loadLinks方法直接调用同一个类中的saveLink,此时saveLink上的事务注解完全不生效,自然无法回滚JobOffer的保存操作。
解决方法
方法1:将事务方法抽取到独立Bean中
把saveLink方法移到一个单独的Service类里,比如JobLinkTransactionalService,然后在原类中注入这个Bean,通过代理对象调用事务方法:
// 新建独立的事务Service @Service public class JobLinkTransactionalService { @Autowired private JobOfferRepository jobOfferRepository; @Autowired private JobLinkRepository jobLinkRepository; @Transactional(rollbackFor = DataIntegrityViolationException.class) public void saveLink(String singleLink) { try{ JobOffer jobOffer = jobOfferRepository.save(JobOffer.builder().id(UUID.randomUUID()).build()); JobLink jobLink = JobLink.builder() .jobLink(singleLink) .jobOffer(jobOffer) .isProcessed(false) .category("Kotlin") .id(UUID.randomUUID()) .timeOfAddition(LocalDateTime.now()) .remote(true) .build(); jobLinkRepository.save(jobLink); } catch (Exception e){ throw new DataIntegrityViolationException("Exception occured during saving link!"); } } }
原类中注入并调用:
@Autowired private JobLinkTransactionalService transactionalService; @GetMapping("/loadLinks") public ResponseEntity<?> loadLinks(){ List<String> allLinks = List.of("https://my-domain-sobs.com/pl/job/mid-dev"); for (String singleLink : allLinks) { transactionalService.saveLink(singleLink); } return ResponseEntity.ok().build(); }
方法2:使用AopContext获取代理对象(不推荐,耦合性高)
如果不想拆分类,可以开启Spring的代理暴露,通过AopContext.currentProxy()获取当前类的代理对象,调用代理的saveLink方法:
- 首先在启动类或配置类上添加
@EnableAspectJAutoProxy(exposeProxy = true) - 修改
loadLinks中的调用逻辑:
@GetMapping("/loadLinks") public ResponseEntity<?> loadLinks(){ List<String> allLinks = List.of("https://my-domain-sobs.com/pl/job/mid-dev"); for (String singleLink : allLinks) { // 通过代理对象调用事务方法 ((YourCurrentClass) AopContext.currentProxy()).saveLink(singleLink); } return ResponseEntity.ok().build(); }
额外检查点
- 确认你的项目已经正确配置了Spring事务管理(比如添加了
@EnableTransactionManagement注解) DataIntegrityViolationException属于RuntimeException子类,其实@Transactional默认就会对RuntimeException触发回滚,你指定rollbackFor是可行的,但不是问题的核心
内容的提问来源于stack exchange,提问作者merc-angel
相关产品推荐
相关产品推荐

