在事物过程中出现异常终止时,后续的内容不再执行,但之前的插入操作依然没有回滚。

声明式注解事务失效原因,主要由以下几点:

  • 方法可见性@Transactional 仅在 public 方法上生效。
  • 自调用:当类中的方法调用同一个类中的另一个 @Transactional 方法时,事务可能不会生效。这是因为事务注解是通过 AOP 实现的,而 Spring 的 AOP 代理机制在这种情况下不会被触发。
  • 异常处理:只有 RuntimeExceptionError 类型的异常会触发事务回滚。如果你抛出的是 checked exception,事务不会回滚,除非你明确指定 rollbackFor 属性。
  • 代理对象:确保你是在 Spring 管理的代理对象上调用方法。如果你直接使用 new 关键字实例化对象,Spring 的 AOP 代理机制将不会被应用。

很显然,自调用这种情况很容易出现,可以替换为编程式事务

public Long userRegisterByPhone(String phone) {  
    return transactionTemplate.execute(status -> {  
        try {  
            // 获得全局自增的用户编号  
            Long ojId = redissonClient.getAtomicLong(RedisKeyConstants.ONLINEJUDGE_ID_GENERATOR).incrementAndGet();  
  
            // 新建用户实例  
            User user = User.builder()  
                    .userAccount(phone)  
                    .userPassword(DigestUtils.md5DigestAsHex((SALT + phone).getBytes()))  
                    .userName("用户" + ojId)  
                    .phone(phone)  
                    .userState(UserStateEnum.LOGOUT.getValue())  
                    .userRole("common_user")  
                    .ojId(ojId)  
                    .build();  
  
            // 插入到数据库  
            this.save(user);  
  
            // 获取刚刚插入的用户的数据库id  
            Long userId = this.baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOjId, ojId)).getId();  
  
            // 分配角色  
            TUserRoleRel userRoleRel = TUserRoleRel.builder()  
                    .userId(userId)  
                    .roleId(RoleConstants.COMMON_USER_ROLE_ID)  
                    .createTime(LocalDateTime.now())  
                    .updateTime(LocalDateTime.now())  
                    .isDeleted(DeletedEnum.NOT_DELETED.getValue())  
                    .build();  
            userRoleRelService.save(userRoleRel);  
  
  
            // 角色信息存入 redis            
            List<Long> roles = Lists.newArrayList(RoleConstants.COMMON_USER_ROLE_ID);  
            String redisRolesKey = RedisKeyConstants.buildUserRoleKey(ojId);  
            redissonClient.getBucket(redisRolesKey).set(JsonUtil.toJsonString(roles));  
  
            return userId;  
        } catch (Exception e) {  
            status.setRollbackOnly(); // 标记事务为回滚  
            log.error("==> 系统注册用户异常: ", e);  
            return null;  
        }  
    });  
}