@Transactional 标了却没开事务?先看这次调用有没有经过代理

我见过不少项目把这个问题归因成「注解没扫到」。但如果注解明明在、Bean 也正常,先别急着查配置。

多数时候,是调用没经过 Spring 的事务代理。

同一个类里这么调,saveOrder 不会被拦截

java 复制代码
@Service
public class OrderService {

    public void createOrder() {
        saveOrder();
    }

    @Transactional
    public void saveOrder() {
        orderRepository.save(new Order());
    }
}

请求进来时,外层确实会先经过 OrderService 的代理。

可 createOrder() 运行起来以后,调用 saveOrder() 用的是当前对象的 this。它没有再绕回代理,所以事务拦截器根本看不见这次调用。

这也是为什么调试时常会觉得很别扭:@Transactional 就贴在方法上,断点也进来了,实际却没有事务。

Spring Framework 的事务文档把这个行为说得很直白:默认代理模式只拦截从代理进入的外部调用,同一对象内部的自调用不会触发事务。

业务入口和事务方法拆开,调用路径就清楚了

我更常用的写法是把编排和落库拆成两个 Bean:

java 复制代码
@Service
@RequiredArgsConstructor
public class OrderFacade {
    private final OrderService orderService;

    public void createOrder() {
        orderService.saveOrder();
    }
}

@Service
public class OrderService {

    @Transactional
    public void saveOrder() {
        orderRepository.save(new Order());
        inventoryRepository.decrease();
    }
}

这里 OrderFacade 注入的是 OrderService 的代理,调用 saveOrder() 时才会进入事务边界。

如果事务本来就该覆盖整个 createOrder(),那就直接把注解放在入口方法上,内部再调私有的辅助方法。别为了「让注解生效」专门搞自注入,调用链会越来越难看。

事务开了,也不等于所有异常都会回滚

还有一个面试里很容易接着问的点:

java 复制代码
@Transactional
public void saveOrder() throws IOException {
    orderRepository.save(new Order());
    throw new IOException("network error");
}

默认规则下,RuntimeException 和 Error 会触发回滚,受检异常不会。上面这段如果没有额外配置,写入仍可能提交。

需要把受检异常也纳入回滚时,明确写出来:

java 复制代码
@Transactional(rollbackFor = IOException.class)
public void saveOrder() throws IOException {
    orderRepository.save(new Order());
    throw new IOException("network error");
}

排查事务问题时,我一般先看日志里是不是出现了事务边界,再看调用是不是绕过了代理,最后才检查传播行为和回滚规则。

相关推荐
Mikko728 分钟前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
.Bryce.35 分钟前
从零到一开发技术名词大全:从需求分析到 AI Agent 工程
java·网络·人工智能·agent·需求分析·agent评测
SL_staff1 小时前
JVS-APS的7个刚性约束设计:从无限产能幻觉到可执行排产的工程实践
java·spring cloud·全栈
代码山河2 小时前
基本类型转换:自动类型转换与强制类型转换
java·学习·架构·教程·面向对象·项目
Escalating_xu3 小时前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络
程序猿乐锅4 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Java后端的Ai之路4 小时前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
Flynn Liang4 小时前
Spring AI 上生产:限流熔断、密钥与成本治理、私有化/混合部署、降级与 Prompt 灰度架构全解
人工智能·spring·架构·高可用·springai·成本治理·生产架构
AntsData5 小时前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat5 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm