SpringBoot中@Transactional注解失效,TransactionManager不工作求助
问题描述
使用@Transactional注解更新UserEntity的nick字段时,服务层能正常获取URL传入的新nick值,但事务完全不生效。预期UserService的updateProfile方法执行时,TransactionManager会开启事务并生成代理对象更新数据库,实际无任何效果。日志显示TransactionSynchronizationManager.isActualTransactionActive()返回false,且无transactionManager启动日志。该功能之前运行正常,现已确认遵循@Transactional注解使用规则,但问题依旧。
技术环境
- SpringBoot 3.1.1
- Java 17
相关代码
UserApiController.java
@Slf4j @RestController @RequestMapping("/api/users") @RequiredArgsConstructor @Validated public class UserApiController{ @EmailAuth @PostMapping("/email-auth-completion/{code}") public ResponseEntity verifyEmail(@PathVariable("code") String code) { log.info("[실행] UserApiController.verifyEmail"); Map<Object, Object> data = redisUtil.getEmailCertification(code); log.info("[정보] " + redisUtil.getEmailCertification(code).toString()); userService.updateEmailAuth(data); return ResponseFormat.RESPONSE_OK; } }
UserService.java
@Slf4j @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class UserService { @Transactional public void updateProfile(ProfileUpdateReqDto reqDto, Long id) { log.info("[실행] updateProfile" + id); log.info("[정보] 트랜젝션 포함 여부 : " + TransactionSynchronizationManager.isActualTransactionActive()); log.info("[정보] reqDto.getNick() : " + reqDto.getNick()); User user = Optional.ofNullable(userRepository.findByid(id)).orElseThrow( () -> new CustomException(ErrorCode.NOTFOUND_USER)) .get(); log.info("[정보] user : " + user.toString()); if (checkNickDuplication(reqDto.getNick())) { throw new CustomException(PARAM_NICK, ErrorCode.DUPLICATE_USER_NICK); } log.info("[정보] 트랜젝션 포함 여부 : " + TransactionSynchronizationManager.isActualTransactionActive()); user.updateProfile( reqDto.getProfileImage(), reqDto.getNick() ); } }
排查方向与解决方案
检查事务管理器是否正常初始化
在配置文件中添加DEBUG级别的日志,查看事务管理器的启动日志:logging.level.org.springframework.transaction=DEBUG logging.level.org.springframework.orm.jpa=DEBUG若没有事务管理器初始化日志,检查是否通过
spring.autoconfigure.exclude排除了DataSourceTransactionManagerAutoConfiguration,或手动配置的事务管理器存在错误。确认代理模式与方法可见性
SpringBoot 3默认使用CGLIB代理,需确保:- UserService类不是final类
- updateProfile方法不是final方法(final方法无法被CGLIB代理,导致事务注解失效)
排查内部方法调用问题
检查是否存在UserService内部无@Transactional注解的方法调用updateProfile的情况,这种场景下不会触发代理,事务无法生效。必须通过Spring容器注入的代理对象调用该方法。验证@Transactional注解配置
确认注解未指定错误的transactionManagerBean名称;多数据源场景下需明确指定对应事务管理器。检查组件扫描范围
确认UserService所在包被Spring组件扫描覆盖,@Service注解被正确识别,否则不会生成事务代理对象。
内容的提问来源于stack exchange,提问作者stonage

