知识卡片

本地事务保证数据库写入与事件发布的原子性

专业/工作 · 525.d

内容

下单成功后既要把订单存进数据库,又要往消息代理发一条”订单已接受”的事件,这两个动作必须是一个整体——要么都成功,要么都不发生,否则会出现数据库有订单但下游从来没收到通知,或者反过来下游已经在处理一个数据库里根本不存在的订单这类不一致状态。这类”横跨数据库和消息代理两种不同资源的一致性问题”是分布式事务的经典难题,saga 模式提供了不依赖笨重的两阶段提交的替代思路,而这里用的是更朴素的一种具体手法:把”写数据库”和”发消息”都包进同一个本地事务里,同时要求消息代理这端的生产者显式开启事务支持,让它也能参与进这个本地事务,两个动作因此被绑定成一个不可分割的单元。发散:这提醒了一个容易被忽视的坑——很多人默认”发消息”是无副作用、不需要考虑事务的操作,但只要它和一次数据库写入在业务上是同一件事,不把两者绑进同一个事务边界,就等于给系统埋了一个只有在网络抖动或进程崩溃时才会暴露的不一致性炸弹。

参考来源

《Cloud Native Spring in Action》第10章《Event-driven applications and functions》