Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q36: 如何处理数据库事务?

核心结论

事务的价值不是“把一切都包起来”,而是在必要边界内保证一组修改要么都成功,要么都失败。

在线游戏里最重要的不是背 ACID,而是先判断:

  • 这条链路是否真的需要事务
  • 事务边界能不能控制在单库单对象附近
  • 超时、重试、幂等和审计是否同时设计了

很多系统的事故,不是因为没有事务,而是把事务用在了错误位置,或者错误地指望事务解决所有一致性问题。

一、哪些场景特别需要事务

通常包括:

  • 扣钱加道具
  • 邮件领取附件并标记已领
  • 交易确认时的多表更新
  • 拍卖成交的状态切换

这类操作有一个共同点:

  • 结果必须原子
  • 中间状态不能暴露

二、事务边界越小越好

事务不是越大越稳,往往恰恰相反。

大事务常见问题:

  • 锁持有时间长
  • 冲突概率高
  • 回滚成本高
  • 故障影响范围大

更稳妥的原则通常是:

  • 只包必要 SQL
  • 尽量不把外部 RPC、网络等待、复杂业务计算放进事务

三、本地事务和分布式事务不是一回事

1. 本地事务

适用于单数据库内的一组更新,是最常用也最可靠的事务形式。

2. 分布式事务

跨服务、跨库、跨队列时问题会复杂得多。

很多在线游戏并不会在主链路大量使用分布式事务,而是更偏向:

  • 单权威写入
  • 幂等
  • 事件驱动
  • 补偿

因为强行把所有跨服务链路做成分布式事务,代价通常很高。

四、隔离级别要按冲突模型选

隔离级别不是越高越好。

更高隔离通常意味着:

  • 吞吐更低
  • 冲突更多
  • 延迟更高

实际选择要看:

  • 是否会出现并发扣减
  • 是否有范围查询
  • 是否担心幻读

很多业务并不需要最高隔离级别,但必须配合正确的更新方式,例如条件更新、版本号或行锁。

五、死锁是设计问题,不只是数据库问题

死锁常见原因包括:

  • 多事务访问资源顺序不一致
  • 大事务持锁过久
  • 一次事务更新太多对象

常见治理手段:

  • 固定访问顺序
  • 缩小事务范围
  • 失败后有限重试
  • 加监控和慢事务排查

六、事务和幂等要一起看

事务保证的是一段数据库修改的原子性,不保证“外部重试不会重复执行”。

例如客户端超时重试时,即使第一次事务已经成功,第二次请求仍可能再次进入。

所以关键写操作通常还需要:

  • 请求唯一 ID
  • 幂等保护
  • 流水记录

七、工程上更稳妥的处理方式

很多核心链路会采用:

  • 单库内关键步骤用本地事务
  • 跨服务修改改成事件驱动
  • 外层请求做幂等
  • 关键结果保留流水

这样能把事务用于它最擅长的边界,而不是滥用。

八、常见误区

1. 所有写操作都应该开事务

不对。事务有成本,很多单语句原子更新并不需要额外大事务。

2. 事务能解决跨服务一致性

单库事务不行,跨服务还需要额外机制。

3. 用最高隔离级别最安全

很多时候只是更慢、更容易冲突,并不一定更适合业务。

参考资料

  • MySQL / InnoDB 事务与隔离级别资料
  • 各类在线游戏资产链路本地事务与幂等实践资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu