[特殊字符] 分布式事务中,@GlobalTransactional 与 @Transactional 到底怎么配合用?

在微服务架构中,随着系统模块的拆分,单体应用中的本地事务已经无法满足跨服务的数据一致性需求。此时,我们就需要引入分布式事务解决方案,比如 Seata。在使用 Seata 的过程中,很多人会遇到一个常见的疑问:

💬"我在调用方加了 @GlobalTransactional,服务提供方还需要加 @Transactional 吗?"

答案是:必须要加!

这篇文章我们就深入讲清楚:为什么服务提供方还需要加 @Transactional,以及两者如何协作实现真正可靠的分布式事务。


🧩 一、事务的两种类型

在讨论这个问题之前,我们先要明确两个事务注解的含义。

✅ 1. @GlobalTransactional(Seata 分布式事务)
  • 加在调用方法上,表示开启一个全局事务

  • 属于 Seata 的 AT 模式 事务注解,由 Seata 的 Transaction Coordinator (TC) 负责协调。

  • 它会自动传播全局事务上下文给远程调用的服务。

✅ 2. @Transactional(Spring 本地事务)
  • 加在某个服务的方法上,表示方法内部的数据库操作需要 在同一个本地事务中进行

  • 只有方法内部的操作在同一个本地事务中,Seata 才能在全局事务失败时,正确地让这些操作回滚。


📌 二、真实业务场景还原

我们以一个真实的订单系统为例:

👇 业务流程:
  1. 用户在订单服务(A)中下单。

  2. 系统同时调用库存服务(B)扣减库存。

  3. 库存服务还会记录一条扣减日志到另一个表。

❗ 错误示范(服务B没加 @Transactional):
复制代码
// A服务
@GlobalTransactional
public void createOrder() {
    orderMapper.insert(order);
    inventoryFeign.decreaseStock(); // 远程调用 B 服务
}

// B服务
public void decreaseStock() {
    stockMapper.decrease();   // 成功
    logMapper.insertLog();    // 失败,抛异常
}

这时候会发生什么?

  • A服务使用 @GlobalTransactional,Seata 启动了全局事务。

  • B服务没有使用 @Transactional,所以两个表的操作并不在同一个本地事务中

  • 如果 logMapper.insertLog() 抛出异常,虽然 Seata 会通知回滚,但由于 stockMapper.decrease() 已经提交,数据就不一致了!

✅ 正确示范(服务B加上 @Transactional):
复制代码
// B服务
@Transactional
public void decreaseStock() {
    stockMapper.decrease();   // 与下方操作属于同一个本地事务
    logMapper.insertLog();
}

现在当 logMapper.insertLog() 抛出异常时:

  • Spring 会将整个 decreaseStock 方法回滚。

  • Seata 能检测到异常,通知所有参与者事务回滚。

  • 整个流程变成原子性的。


🔍 三、Seata 的本质:全局事务 + 本地事务协同

Seata 做的不是"接管"你的数据库事务,而是:

在每个服务节点中使用代理数据源(DataSourceProxy),通过拦截本地事务的提交/回滚操作,来实现 全局的一致性控制

因此:

  • @GlobalTransactional 控制"何时开始、是否提交全局事务"

  • @Transactional 保证"本地数据库操作的一致性和可回滚性"

你不加 @Transactional,Seata 就没法让你的数据库事务回滚,因为根本没事务!


🛠 四、项目接入建议

如果你要使用 Seata 进行分布式事务控制,务必注意以下几点:

配置项 说明
✅ @GlobalTransactional 放在业务流程发起方(一般是 Controller 或 Service)
✅ @Transactional 放在服务提供方处理数据库操作的 Service 方法上
✅ 使用 Seata 的 DataSourceProxy 所有数据源都要通过 Seata 的代理包装
✅ 注册到 Seata Server 服务注册中心需正确配置 Seata 服务

📚 五、总结

@GlobalTransactional 是分布式事务的起点,@Transactional 是本地事务的保障,二者缺一不可。

在微服务的世界里,要实现数据一致性,必须让每个参与者都对自己的事务负责。Seata 会协调所有本地事务的提交和回滚,但它不会、也无法替你加上事务控制。


如果你觉得这篇文章对你有帮助,欢迎点赞、评论、收藏 ✅

有任何问题也欢迎私信或留言交流!


📌 附推荐阅读:

相关推荐
jackson凌10 分钟前
【Java学习笔记】equals方法
java·笔记·学习
TinpeaV17 分钟前
websocket入门详解
java·网络·spring boot·websocket·网络协议
王有品21 分钟前
Java 集合框架对比全解析:单列集合 vs 双列集合
java·windows·python
北漂老男孩24 分钟前
ChromeDriver 技术生态与应用场景深度解析
java·爬虫·python·自动化
-曾牛28 分钟前
基于微信小程序的在线聊天功能实现:WebSocket通信实战
前端·后端·websocket·网络协议·微信小程序·小程序·notepad++
MMMMMMMMMMemory29 分钟前
pgsql14自动创建表分区
数据库·pgsql
文牧之33 分钟前
PostgreSQL 配置设置函数
运维·数据库·postgresql
昔我往昔1 小时前
除了GC哪些地方有用到安全点
java·jvm·安全
wxin_VXbishe1 小时前
springboot旅游小程序-计算机毕业设计源码76696
java·spring boot·python·spring·django·sqlite·flask
我是Superman丶1 小时前
【Lua】java 调用redis执行 lua脚本
java·开发语言·junit