REA业务建模实战:资源-事件-代理者模型重构进销存系统

发布时间:2026/10/21 14:54:28
REA业务建模实战:资源-事件-代理者模型重构进销存系统 做业务系统的人大概都遇到过一种尴尬财务那边要一套账运营那边要一套报表研发手里那几张表结构却经常在两者之间反复横跳。数据是同一批数据但口径一多系统就成了一层层补丁堆出来的模型。我第一次真正理解 REAResources-Events-Agents资源-事件-代理者模型就是在这种背景下。当时被拉去评审一个进销存系统的重构方案某导师在会上说了一句话我记到现在你们这张库存流水表本质上是一张事件表但你们一直在拿它当资源表用。这句话我琢磨了很久也促使我把 REA 从理论到落地完整啃了一遍。这篇文章就打算把那次项目里用 REA 做业务建模的完整思路、表结构设计、查询逻辑和踩过的坑原原本本分享出来。REA 不是什么新框架它最早是会计信息系统领域里提出来的一套语义模型后来被越来越多的人应用到企业系统、数据仓库、审计追踪的设计上。简单说它主张把业务世界还原成三种东西资源Resource、事件Event、代理者Agent。你不需要懂会计也能用因为它的本质是回答一个问题系统里到底发生了什么。如果你正在设计进销存、订单、账单、权限或者审计模型这篇文章值得你花十分钟看完哪怕你只是写一个小项目理解这套思路也能帮你避开很多改表结构改到崩溃的坑。1. 传统记账思维给系统设计埋了哪些坑1.1 借货、贷货的思维惯性接触 REA 之前很多系统设计者习惯用会计科目或者单据类型来主导表结构设计。比如拿到一个出库单第一反应是建一张出库单主表、一张出库单明细表拿到入库单又建一对主表和明细表。单据越堆越多于是每次新增业务——比如加一个调拨或者盘点——就要再补两张表或者拼命给现有表加类型字段。这个思路不能说是错的但它把业务动作和业务结果的记录载体混在了一起。我用一个生活化的类比来解释。传统记账思维像是给每个房间都装了独立电表厨房一个、卧室一个、客厅一个每个电表只记录自己房间的用电。问题是当你想知道整栋房子今天一共用了多少电时你不得不把所有电表读数手动加一遍如果某个电表坏了或者你想单独问空调那一路电用了多少可能就无能为力了。REA 的思路更像是一个总闸日志它记录每一个用电事件本身——什么时候、在哪条线路、流了多少电、是谁触发的。至于每个房间分摊多少反而是可以随时重新计算的。1.2 发生什么比记成什么更重要REA 模型的核心主张是把事件放在中心位置。所谓事件就是业务世界里真实发生的动作顾客下单、仓库发货、收到货款、退回商品、盘点调整。这些事件在时间轴上自然排序构成了系统的时间线。而资源也就是钱、货、服务、积分这些有价值的东西是事件作用的对象代理者比如顾客、销售员、仓库管理员、供应商是事件的发起方和接收方。这个视角最大的好处在于它不预设你将来要用什么科目、什么单据来承载业务系统因此可以更贴近真实业务过程也更容易适应业务规则的变化。举个例子你原来把发货当成一张单据表后来业务改成先出库、后记账甚至把发货拆成拣货—交接—签收三件独立的事基于单据模式的表结构就得伤筋动骨。但如果底层是事件表新增一个事件节点而已历史数据完全不用动。1.3 什么人适合认真学这套东西先泼一盆冷水如果你只是写一个轻量级的个人项目比如一个小型记账本直接用一张流水表就完全够用不必上 REA。但一旦系统要同时服务财务、供应链、销售、运营这些不同口径的部门或者你需要应对审计追溯、数据仓库建模、跨系统对账这类需求REA 能帮你省掉大量重建口径的工单。这也是我把它定位成给多业务口径系统建模的地基的原因。2. 资源-事件-代理者的三元结构用大白话拆开2.1 资源Resource跟着钱和物走资源不是资产负债表上的科目它指的是系统里被管理、被交换、有价值的东西。常见候选有商品库存、现金及等价物、应收账款、积分、服务时长、数字资产。判断一个对象是不是资源有一个简单标准它能不能被某个事件改变数量或者归属。比如一件商品出库事件让它的数量减少一笔现金收款事件让它的余额增加。如果某个对象只是依附于其他对象的描述性信息比如订单备注那它就不是资源。这里要特别注意资源和资源之间往往有父子关系。例如商品是一个资源某个批次的商品也是一个资源前者可以聚合后者。在 REA 建模里资源体系完全可以做多层级关键在于把层级关系当成资源与资源之间的关联而不是用一张大宽表把层级信息全部拍扁。2.2 事件Event系统的时间线事件是 REA 里最富有启发性的概念。它记录的是业务过程中一个不可再细分的动作。怎么判断不可再细分看两个动作能否被合并成一条记录而不丢失关键信息。还是以发货为例顾客下单和仓库发货是两个不同时间点、不同责任主体做的事必须拆成两个事件而录入订单和确认订单如果发生在同一时间、同一个人、同一个系统界面理论上可以合并成一条但为了审计可追溯通常还是建议拆开。事件表在实际落地时往往就是一张流水总账。任何业务表只要它描述的是一个动作而不是一个静置的对象都应该考虑用事件的逻辑来建模。我见过不少团队把订单表设计成什么都往里塞金额、状态、地址、优惠信息一个典型的事件被对象化问题后面每加一个业务环节就要加一堆字段。2.3 代理者Agent责任边界靠它画出来代理者是事件的参与方既可以是自然人也可以是组织或角色。为什么要把组织单独拎出来因为现实中经常出现张三作为采购员替某公司采购的场景如果不区分张三和某公司这两个代理者维度审计时根本说不清楚责任和权限。REA 里的事件关联建议至少保留两个代理者角色从某代理者和到某代理者这样买卖双方、收发双方都能被完整记录。有些系统把客户做成用户表里的一个类型字段又另外建一张客户信息表再去关联订单。字段越加越多最后客户、供应商、内部员工三套身份混在一起。用 REA 去澄清责任边界时你会发现代理者就是一类对象和具体业务角色解耦角色只是关系上的标签而已。2.4 三类关系连起来业务就变成了闭环资源、事件、代理者不是三个孤立的概念而是靠关系组织起来的。资源与事件之间是参与关系出库事件减少了商品库存资源事件与代理者之间是执行/接收关系仓库管理员执行了出库承运方接收了货物资源和事件之间还可以有转换关系生产事件把原材料资源转换成产成品资源。把这些关系画清楚系统里的业务流就不再是散落的表单而是一张可以追溯每个动作由谁做、对什么做、影响什么的因果图。3. 用一个电商案例完整走一遍 REA 建模3.1 场景设定模拟项目X的下单—库存—回款链路为了让上面的概念落到实处我拿一个模拟项目X来演示。这是一个小型电商系统业务链路不算复杂顾客浏览商品、下单、支付仓库拣货并发货顾客确认收货平台与供应商结算货款。传统做法里我们会设计商品表、订单表、订单明细表、支付单表、发货单表、结算单表。用 REA 视角走一遍会发生什么变化先划元素。资源方面有商品库存和资金两类事件方面涉及五个核心动作顾客下单、顾客支付、仓库发货、顾客收货触发平台确认收入、平台向供应商付款代理者包括顾客、平台自身、仓库管理员、供应商。注意我没有把订单列为资源因为订单不是一个有价值的东西它是多个事件的组织外壳真正有价值的资源是商品和资金。3.2 从业务单据反推事件链这一步我建议逐张单据过一遍每张业务单据都想清楚这张单子是在描述一个动作还是在描述一组状态。发货单显然是在描述发货这个动作所以它应该对应一个事件订单则更像是把下单、支付、收货这些事件聚合在一起的一个业务根对象数据库里仍然可以保留一张订单主表作为聚合头但它不应该承担记录业务动作的全部职责。把事件拆出来之后接下来要为每个事件找到两个代理者——谁发起、谁接收——以及受影响的那一项资源。比如顾客下单事件发起方是顾客接收方是平台但它直接影响的是商品库存吗并不是。下单本身还没改变库存它改变的其实是顾客和平台之间的一项合约关系。你可以把订单应付/应收建模为一项资源也可以暂时让下单事件不直接作用于商品资源。这个区分在后面建模资金时会显得尤为重要。3.3 建模结果与表关系示例我用一张表格把核心事件的归属说清楚事件发起代理者接收代理者影响的资源事件结果提交订单顾客平台应收/应付合约合约增加完成支付顾客平台资金账户资金平台资金增加仓库发货仓库管理员承运方/顾客商品库存库存减少确认收货顾客平台应收/应付合约合约完结确认收入有了这张表数据库里的事件表就可以统一设计成一张动作流水表每行记录一个事件包含事件类型、发生时间、发起代理者、接收代理者、关联资源、数量、金额等信息。不同业务类型之间的事件差异用类型字段区分或者再用事件扩展表存放各自的附加属性事件表本身保持精简。4. 落地到数据模型表结构、外键与典型查询4.1 事件表怎么设计才不变成垃圾桶很多人看到把所有事件放进一张表第一反应是它会不会变成一张无法维护的大杂烩。确实会如果不做约束的话。我的经验是事件表只承载公共动作属性事件ID、所属聚合比如订单号、事件类型、事件时间、发起代理者、接收代理者、关联主资源、变化数量、变化金额、备注。各业务特有的扩展信息放到扩展表里通过事件ID一对一关联。这里要特意提醒一个细节事件表中数量和金额必须设置严格的符号约定。例如增加资源记正数减少资源记负数流入资金记正数流出资金记负数。这样一组 SUM 即可统计出任何资源的余额变化避免在代码里为每种业务各写一套加减逻辑。这是我吃过亏的地方一开始没有统一符号约定后面所有统计查询都变成一条业务一套 SQL维护成本高到想哭。4.2 资源表与事件表怎么关联资源表存的是当前状态事件表存的是历史动作这两个概念千万不要合并成一张表。以库存为例商品库存资源表里维护的是当前可用数量每个出库/入库事件都往事件表里写一笔带正负号的数量记录把事件表按时间累加就能随时回放出任意时间点的库存快照。这正是事件溯源思想在业务系统里的一种落地方案REA 和事件溯源天然契合。表与表的基本关联可以这样设计事件表里有多列代理者外键分别指向代理者表的不同实例资源表与事件表通过关联资源外键相连。实际操作中有人把代理者和资源统一放到一张业务对象大表里再用类型区分也有人分成几张业务身份表事件表里用多个可空外键指向它们。两种方案我都试过单表简单但类型容易混乱分表清晰但关联稍重。团队规模不大时我更推荐分表。4.3 典型查询库存、毛利、对账怎么算建模之后很多查询都变得非常直接。比如统计某天某商品的库存余额select resource_id, sum(qty_change) as balance from rea_event where event_time 2025-06-30 23:59:59 and event_type in (入库, 出库, 盘点调整) group by resource_id;再比如按代理者统计一段时间内的销售额select agent_id, sum(amount) as sales_amount from rea_event where event_type 确认收入 and event_time between 2025-01-01 00:00:00 and 2025-06-30 23:59:59 group by agent_id;这种写法有个很实在的好处事件表里存的是原始动作只要设置不同的查询条件就能同时回答财务、运营、审计三方的不同口径而不是每换一个报表口径就要改表结构或重新导数据。很多同事第一次看到这套查询时都觉得太简单了但简单恰恰说明建模方向对了。5. 实践中的坑与经验哪些地方别照搬 REA5.1 最容易搞混的把资源当事件、把事件当单据第一次用 REA 建模的朋友最容易把商品这类静置对象当成事件又把发货单这类单据当成事件。把商品当事件问题在于对象的当前数量是状态不是可以按时间线查询的动作把发货单直接映射成事件问题在于一张单据往往是对多个动作的包装直接映射会丢失动作之间的时间差和责任划分。我的判断方法是每次先问自己——这一行记录表示的是一次时间点上的一个动作还是此刻某个东西的状态如果是前者它就是事件如果是后者大概率是资源。再问一句这个动作有没有明确的发起方和接收方如果没有那很可能建模粒度太粗或者它只是一个大动作里的辅助步骤不应该单独成事件。5.2 资金类资源怎么建模资金是 REA 实践里最容易翻车的点问题通常出在应收应付余额这些概念被混成一张表。按 REA 的做法顾客支付事件会同时影响两个资源顾客侧资金减少、平台侧资金增加。而应收/应付最好建模成一项合约类资源它不是资金的子类而是连接履约状态的一种待结转权利义务。只有把钱实际在哪和谁还欠谁多少分成两类资源对账逻辑才能写清楚。具体到表结构我建议资金账户表只反映真实可用的资金余额所有变动都来自严格校验过的支付/退款事件另建一张应收应付合约表记录订单维度上的债权债务定期或按需做核销。这种拆分乍看有点绕但分摊成本极低还能彻底避免账面余额和实际余额永远差一分钱的悲剧。5.3 哪些业务场景不适合 REAREA 不是万能模板它最大的短板在于模型抽象度高团队成员水平参差时反而会增加沟通成本。比如一次纯展示性质的需求只需要把几个第三方接口的返回结果透传到前端就没有必要硬套 REA又比如一个生命周期很短的临时活动建一堆事件表纯属浪费。我自己的判断标准是三条系统未来有没有明确的审计需求、有没有跨渠道多口径的需求、有没有跨部门对账的需求。只要有其中一项REA 都值得引入如果都没有用简约的表单驱动设计反而更快。再补充一点不要试图用 REA 消灭所有订单表这类聚合实体。订单作为一组事件的聚合组织者仍然有存在的价值只是它的身份从存储业务的容器变成了关联多个事件的根对象两者并不矛盾。5.4 落地推进的个人建议如果团队之前没接触过这类模型不建议一上来就全量重构。我第二次实践 REA 时学乖了先挑选业务链路里最容易出问题的部分通常是库存回款这对组合用 REA 重新建一套事件流水然后让报表、对账、审计三个场景都基于这套流水开发跑通后再逐步把更多业务纳入进来。这样既降低了改革阻力也能用实际效果说服其他成员。还有一点容易被忽略事件表数据量会长得很快必须从第一天就规划归档策略比如按月分区、冷热分离不要让一张原始事件表占用主库大量空间。事件数据的价值在于可以被反复查询查询性能与存储成本之间需要持续做平衡。其实在我个人的实际操作体会里REA 给我最大的启发不是什么高深理论而是先想清楚业务里每一次到底发生了什么再去谈怎么存、怎么算。在系统越来越复杂的今天这种把业务还原成资源—事件—代理者因果网络的方法反而让设计变得简单了。如果你也正在为库存对账、审计追溯这类问题头疼不妨拿手头一个真实业务链路试一次 REA 建模。哪怕最终不重构光是把事件链完整画出来就足以让很多隐藏的设计问题现形。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询