干开发这些年,交易类的系统我前后碰了不少,从最早的电商订单模块,到后来独立负责交易中台,最大的感触是:交易中台不是一个"项目",而是一套"设计哲学"。你代码写得再快,如果边界划不清、模型建不对、状态机设计得乱,后面就是无穷无尽的补丁和线上事故。
这篇文章我不讲空泛的概念,就聊聊我在真实项目中沉淀下来的交易中台核心设计思路,包括订单模型怎么拆、状态机怎么定、幂等怎么做、支付对账怎么搞、库存扣减怎么防超卖。文中会有大量我能直接落地的方案和踩坑记录,适合正在做交易系统、或者准备从业务系统往中台方向转型的后端同学参考。
1. 交易中台的边界:先想清楚"哪些该做,哪些不该做"
很多团队一上来就画一个大中台蓝图,订单、支付、库存、营销、用户、商品全都要收进中台,结果做了两年还在治理数据。我个人的经验是:交易中台的边界,一定是从"交易链路"出发,而不是从"组织架构"出发。
1.1 交易中台到底管什么
交易中台的核心职责,是承接所有需要"产生交易"的业务方,提供一套统一的交易能力。什么算交易能力?我总结下来就四件事:
- 订单能力:创建订单、查询订单、改订单、取消订单、删除订单(逻辑删)、订单状态流转。
- 支付能力:发起支付、支付回调处理、退款、退款回调、支付单查询。
- 库存能力:库存预占、库存扣减、库存释放、库存查询。
- 履约能力:发货、收货、售后单生成、退货入库。
注意,这四件事不是四个独立系统,而是一条完整链路上的四个环节。中台要做的,是把这四个环节串成一个标准流程,同时对业务方屏蔽底层的渠道差异和状态差异。
1.2 边界没划清会出什么问题
我见过最典型的反面案例:业务方直接对接支付渠道,自己维护支付回调,又自己扣库存。结果同一笔订单,业务A的支付状态是"已支付",业务B的支付状态还是"待支付",因为业务A自己调了渠道查询接口,业务B没有。最后对账的时候,财务拿着账单找过来,两边都觉得自己是对的。
中台的边界如果划不清,就会出现大量这种"局部正确、全局错误"的问题。所以我在设计交易中台的第一天就定了一条规矩:凡是和"钱"、"货"、"状态流转"相关的操作,一律走中台,业务方不许自己碰底层渠道,不许自己维护订单状态。
这条规矩落地的时候会有点痛,因为业务方会觉得"我调你的接口还不如我直接调支付渠道方便"。但等系统稳定下来,大家就会明白,多一次抽象不是多一层损耗,而是多一层保护。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 订单核心模型:一切从订单主档和订单项开始
订单模型是整个交易中台的地基。地基没打好,后面楼层盖得再高都是危房。我在设计订单模型时,最核心的决策是:把订单拆成订单主档(order_main)和订单项(order_item)两层。
2.1 一拆二:订单主档和订单项分开存
为什么一定要拆?因为真实业务里,一个订单可能包含多个商品,而每个商品可能走不同的发货仓、不同的物流、甚至不同的售后流程。如果你只建一张订单表,把所有商品都塞在一条记录里,那么一旦遇到"部分发货""部分退款"这种场景,你的表结构就会变得非常别扭。
拆成两层之后,数据模型大概是这个样子:
sql复制-- 订单主档
CREATE TABLE order_main (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(64) NOT NULL COMMENT '业务订单号,唯一',
buyer_id BIGINT NOT NULL COMMENT '买家ID',
seller_id BIGINT NOT NULL COMMENT '卖家ID',
total_amount DECIMAL(12,2) NOT NULL COMMENT '订单总金额',
pay_amount DECIMAL(12,2) NOT NULL COMMENT '实付金额',
discount_amount DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '优惠总金额',
status TINYINT NOT NULL COMMENT '订单状态',
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL,
UNIQUE KEY uk_order_no (order_no)
) COMMENT '订单主档';
-- 订单项
CREATE TABLE order_item (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(64) NOT NULL,
sku_id BIGINT NOT NULL COMMENT '
