一句话理解

DGJ2.0 是一个围绕服务站经营的进销存系统:上游承接商品、订单、活动、支付、OA、调拨、TMS 等中心系统,下游给 PC 后台、App、小程序、渠道方和报表平台提供业务能力。

技术形态

  • PHP 版本要求:composer.json 中为 php >= 7.1
  • 框架风格:CodeIgniter 老项目,入口控制器在 application/controllers
  • 依赖:Guzzle、Monolog、MongoDB、Redis、Elasticsearch 6.7、PhpSpreadsheet、kz/kzmq、league/csv
  • 自动加载:App\\ 指向 application/
  • 数据访问:大量模型继承老模型基类,模型目录在 application/models
  • 服务层:新老并存,application/Services 偏新,application/service 偏老

入口层

  • application/controllers/scm:传统进销存页面入口,包含采购、销售、库存、收付款、任务。
  • application/controllers/po:新采购相关入口,如采购订单详情、购物车、采购退货。
  • application/controllers/sale:销售和出库相关入口。
  • application/controllers/basedata:基础资料管理,如商品、客户、供应商、库存、价格、区域。
  • application/controllers/inner:内部 API,给 OPS、活动、渠道、移动商城等系统使用。
  • application/controllers/app:App 侧控制器。
  • application/controllers/tasks:定时任务和 MQ 消费入口。
  • application/controllers/reports:报表页面和报表接口入口。
  • application/controllers/allcarpart:全车件相关业务入口。

服务层

  • application/service/scm/InvPoService.php:老采购单列表、详情、关闭、退货展示等逻辑。
  • application/Services/PoOrders/PoOrderSer.php:新采购领域服务,负责订单校验、创建、自制单同步、关闭、支付状态等。
  • application/service/scm/InvSaService.php:老销售出库列表、详情、对账、核销等逻辑。
  • application/Services/SaOrders/SaOrderSer.php:销售订单创建、出库、来源场景转换、库存扣减和下游同步。
  • application/Services/Storage/InventorySer.php:库存流水和实时库存变更。
  • application/Services/Activity/FlashActivitySer.php:OPS 秒杀活动管理。
  • application/Services/Activity/FlashSaleSer.php:服务站侧秒杀商品、购物车、预览、下单、支付状态联动。
  • application/Services/MoveMall:移动商城、智能询价、机器人、补货、马上送。
  • application/Services/Channel:大客户渠道订单、商品、售后。
  • application/Services/Mq/MqSer.php:MQ 生产者封装。
  • application/Services/SyncOrder:销售单和出库单同步到下游。

模型层

常见模型目录和业务含义:

  • application/models/bs:基础资料,商品、库存、客户、供应商、服务站、品牌、分类、账户。
  • application/models/orders:采购单、销售单、预订单、采购关闭、采购出库、付款信息。
  • application/models/saOrders:销售订单、销售出库单、销售异常、品牌统计。
  • application/models/payment:收付款单、明细、还款单。
  • application/models/activity:活动、秒杀活动、秒杀购物车、秒杀订单、活动商品。
  • application/models/moveMall:移动商城、微仓、机器人会话、关键词、补货退货。
  • application/models/channel:渠道订单、渠道订单明细、渠道售后。
  • application/models/report:报表模型。

配置层

  • application/config/routes.php:少量显式路由,多数沿 CI 默认 controller/method 路由。
  • application/config/apis.php:老开放接口 code 到 service 文件映射,例如订单状态、出库、收款成功回调。
  • application/config/appapis.php:App 接口 code 到 app service 文件映射,覆盖登录、商品、销售、采购、资金、系统、WMS、盘点。
  • application/config/mq.php:MQ 配置。
  • application/config/redis.php、memcached.php、mongodb.php、elasticsearch.php:缓存和检索配置。
  • application/config/tables.php:大量表常量来源之一。

外部系统边界

  • 订单中心:采购正向、售后、取消、自制订单下发、关闭。
  • 支付中心:在线支付成功、支付异常、退款、授信还款、白条到期。
  • OA:活动、授信或审批类业务的审批结果。
  • OPS:活动配置、商品活动、品牌授权、白名单等运营能力。
  • 商品中心:物料、结算价、套包、限购、敏感词、销售限价。
  • 调拨中心 / TMS:发货、配送、物流状态、第三方运单号。
  • SAAS / APP:E站商城、E站维修、订单和出库同步。
  • 报表中心 / Hologres:采购、销售、库存、利润等聚合查询。

主链路脑图

基础资料
  -> 商品/客户/供应商/仓库/货位/价格
  -> 采购、销售、库存、活动共用

采购
  -> 草稿 -> 提交 -> 审核/支付 -> 待出库 -> 配送/入库 -> 完成/关闭/退货
  -> 影响采购明细、库存、付款、报表、订单中心

销售
  -> 开单 -> 待出库 -> 出库 -> 派送 -> 送达 -> 对账 -> 核销
  -> 影响库存、收款、客户余额、APP/SAAS 同步

活动/秒杀
  -> OPS 建活动 -> OA 审批 -> 服务站选购 -> 生成秒杀单 -> 生成采购单 -> 支付/关闭回写

移动商城/渠道
  -> 外部订单/询价/机器人 -> DGJ 销售或采购单 -> 库存/支付/配送 -> 外部系统回调

任务/MQ
  -> 支付、OA、订单中心、商品中心、TMS、SAAS 消息
  -> 补偿、同步、状态推进、缓存刷新

系统上下游全景

flowchart LR
    subgraph Clients[调用端]
        PC[PC 后台]
        APP[App/PDA/小程序]
        OPS[OPS/内部平台]
        OPEN[渠道/OpenAPI]
    end

    subgraph DGJ[DGJ2 单体]
        C[Controller/路由]
        S[新旧 Service/Provider/Factory]
        M[Model/SQL]
        CACHE[Redis/ES/Mongo 缓存]
        TASK[Tasks/MQ 消费者]
    end

    subgraph Data[数据结果]
        MYSQL[(MySQL 业务表)]
        REPORT[(Hologres/报表中心)]
    end

    subgraph Centers[外部中心]
        ITEM[商品中心]
        ORDER[订单中心]
        PAY[支付中心]
        OA[OA]
        DISPATCH[调拨/配送/TMS]
        SAAS[SAAS/E站/APP]
    end

    PC --> C
    APP --> C
    OPS --> C
    OPEN --> C
    C --> S
    S --> M
    S <--> CACHE
    M --> MYSQL
    S --> Centers
    Centers --> TASK
    TASK --> S
    MYSQL --> REPORT

DGJ2 是业务编排和服务站账本,不是所有数据的最终权威:商品、订单审核、支付、OA、配送可能由外部中心主导;采购、销售、库存、收付款和服务站经营快照主要落在 DGJ2。排查前要先判断当前字段的主责系统。

五类请求入口

入口路由/解析方式身份上下文典型返回适用场景
PC 页面/接口CI 默认 目录/Controller/method,少量 routes.php 显式映射登录 session 中的 jxcsyssplash、splashJson、ajaxData采购、销售、库存、财务页面
内部 APIapplication/controllers/inner + BaseApiController内部 token、Header、Inspire-Api-UserR/Controller handle 包装OPS、活动、渠道、移动商城
App API codeappapis.php code -> application/service/api/appApp 协议身份、服务站和用户App 统一协议包装App、PDA、WMS、盘点
老开放 API codeapis.php code -> application/service/api外部接口签名/上下文老协议包装历史订单、出库、收款回调
CLI/MQ直接执行 controllers/tasks/*MQ payload 或 CLI 参数ACK/NACK、日志、JSON 输出回调、定时、同步、补偿

显式路由和默认路由

routes.php 只维护少量特殊映射,例如全车件 REST 风格路径。其他大量接口依赖 CodeIgniter 默认规则:URI 片段直接映射 Controller 和方法。因此:

  • 看到 Controller 方法不能立即确定公网 URL,还要看 Nginx/OpenResty、入口文件和网关前缀。
  • 全车件路由存在 kebab-case 到 Controller index/$action 的二次映射。
  • App/OpenAPI 不能只按 Controller 路径寻找,要先从接口 code 找映射值。
  • Tasks 是 CLI/MQ 入口,不应暴露给普通前端直接调用。

PC 请求生命周期

sequenceDiagram
    participant B as 浏览器
    participant N as Nginx/OpenResty
    participant I as index.php/CI Router
    participant C as BaseController/业务 Controller
    participant S as Service/Factory
    participant DB as Model/MySQL
    participant X as MQ/外部系统

    B->>N: GET/POST + session/cookie
    N->>I: 转发到 PHP 入口
    I->>C: 默认或显式路由到方法
    C->>C: 权限检查 + getPageData
    C->>C: 注入 JXCSID/JXCUID/JXCUNAME
    C->>S: 业务参数 + 登录上下文
    S->>DB: 查询/事务/状态更新
    opt 跨系统动作
        S->>X: HTTP/MQ/Provider
    end
    S-->>C: 结果或异常
    C-->>B: splash/splashJson/ajaxData

getPageData() 实际行为

BaseController::getPageData():

  1. 合并 GET 和 POST。
  2. 调用历史参数过滤逻辑。
  3. 把 page 最小归一为 1,rows 缺省为 99999。
  4. 从登录态覆盖注入服务站、用户、区域和所属片区。
注入字段来源用途
JXCSID$this->jxcsys['sid']服务站数据隔离和分表/查询条件
JXCUID登录用户 ID操作人、审计、权限
JXCUNAME登录用户名单据制单人和日志
areaCode服务站区域供应、退货地址、商品规则
eparchy服务站所属区域物料和采购规则

业务 Service 应优先使用服务端注入值,不信任 postData 中同名字段。排查跨站数据问题时,先确认 Controller 是否正确使用 JXCSID,再查 SQL 是否漏了 sid。

内部 API 生命周期

flowchart TD
    A[JSON/Form 请求] --> B[BaseApiController 构造]
    B --> C[解析 Content-Type 和 raw body]
    C --> D[记录 URI/body/header 请求日志]
    D --> E{是否内部服务并需要 token}
    E -- 是 --> F[校验 inner_token]
    F -- 失败 --> X[非法请求]
    E -- 否 --> G[读取 Request-Id/Inspire-Api-User/Shipper]
    F -- 通过 --> G
    G --> H[业务 Controller handle]
    H --> I[Request Entry 归一字段]
    I --> J[领域 Service]
    J --> K[表/缓存/Provider]
    K --> L[统一 JSON 返回并记录日志]

BaseApiController 会读取:

  • Content-Type:JSON 走 raw_input_stream,其他内容合并 GET/POST/raw body。
  • Request-Id:请求追踪标识。
  • Inspire-Api-User:URL 编码 JSON 的 OPS 用户信息。
  • Shipper:部分承运/内部业务上下文。
  • inner_token:满足条件时执行内部服务鉴权。

内部 API 日志默认记录请求 body 和 header。新增接口时禁止把密码、token、支付敏感信息原样写入日志,应在入口或 Logger 层脱敏。

新旧代码分层如何理解

代码形态常见位置典型作用阅读建议
老 Serviceapplication/service页面查询、历史业务编排、直接模型操作先找 Controller 装载的 service 名称
新领域 Serviceapplication/Services领域规则、实体校验、跨入口复用优先找 ::service() 和 public 方法
Providerapplication/Providers远程采购、支付、OA、文件等适配明确远程边界、超时和返回协议
Factoryapplication/Factory 或领域目录按普通销售/销退/订单类型选择实现查字符串类型对应的具体实现
Entry/DTOapplication/Entries请求归一、默认值和领域参数确认兼容别名和单位
Modelapplication/models表查询和写入用 tables.php 常量确认物理表
Enumapplication/KzData/Enums状态、类型、来源、交易类型状态判断和报表过滤的共同证据

同一链路可能是“老 Controller -> 老 Service -> 新领域 Service -> Provider”。不要按目录新旧直接判断是否废弃,要用调用方搜索和环境开关确认。

数据访问和事务边界

flowchart LR
    C[Controller] --> S[Service]
    S --> BM[BaseModel/业务 Model]
    BM --> T[(业务主表/明细表)]
    S --> R[(Redis 锁/缓存)]
    S --> ES[(ES/Mongo)]
    S --> P[Provider/外部中心]
    T --> MQ[MqSer/SyncOrder]
    MQ --> D[下游消费者]

需要特别区分:

  • MySQL 事务只能保证同一连接内的表写入,不能自动回滚已成功的 HTTP/MQ 外部动作。
  • Redis 锁是短时互斥,不等于业务幂等。
  • ES/Mongo/Redis 常是查询或缓存口径,不能用缓存结果替代库存/资金最终校验。
  • 报表中心是异步聚合,允许短时延迟,但不允许长期与业务事实冲突。

三类常见响应

方法典型结构特点
resp{"code":0,"msg":"...","data":{}}标准 code/msg/data
splashJson/splash包含 status/message/data 等历史字段可能直接 _display() 并 exit
ajaxData/直接 die(json_encode())直接输出 Service 返回结构取决于调用 Service

联调前先确认当前 Controller 使用哪一种返回方法。不要因为 HTTP 200 就判定业务成功,也不要强行要求所有历史接口立即改成同一种结构;统一响应属于跨前端契约改造,需要兼容期和完整调用方清单。

业务链路和主数据依赖

flowchart TD
    BASE[服务站/客户/供应商/商品/仓库/货位/价格] --> PO[采购]
    BASE --> SA[销售]
    BASE --> ACT[活动]
    PO --> INV[库存]
    SA --> INV
    ACT --> PO
    PO --> FUND[付款/退款]
    SA --> FUND2[收款/对账/核销]
    INV --> REPORT[报表/利润/经营分析]
    FUND --> REPORT
    FUND2 --> REPORT
    PO --> SYNC[订单中心/支付/OA/配送/SAAS]
    SA --> SYNC
    ACT --> SYNC

主数据错误会沿链路扩散:商品状态、仓库货位、客户账户或服务站区域不正确时,采购、销售、库存、支付和报表可能同时异常。排查业务单前先验证主数据快照和当前资料是否一致。

一次问题的定位顺序

  1. 确认调用端、接口路径/code、环境、服务站和请求时间。
  2. 根据入口找到 Controller 方法,确认请求解析和权限。
  3. 记录主业务键:sid、业务单号、主单 ID、来源类型、来源单号、request ID。
  4. 沿调用链进入 Service/Provider/Factory,列出状态前置条件。
  5. 查主表、明细、数量/金额/日志表,不只看页面状态。
  6. 涉及库存、资金时核对流水事实和实时结果。
  7. 涉及异步时查生产日志、destination/routing key、消费 ACK/NACK。
  8. 查自动补偿是否执行;人工处理前确认幂等和影响范围。
  9. 对比下游和报表,区分实时失败、同步延迟和口径差异。
rg -n "class .*Controller|function 目标方法" application/controllers
rg -n "目标方法|业务单号字段|状态常量" application/service application/Services application/models
rg -n "目标表常量|物理表名" application/config/tables.php application
rg -n "routing key|destination|事件名" application/controllers/tasks application/Services/Mq application/KzData/Enums

系统级改动风险和回归

改动位置主要影响最小回归
BaseController 请求解析/过滤所有 PC 和内部 APIGET/POST/JSON、分页、中文、特殊字符、登录上下文
BaseApiController 鉴权/HeaderOPS、内部系统、渠道合法/非法 token、Request-Id、用户头、日志脱敏
tables.php 常量所有模型读写目标环境表存在、读写权限、历史分表
公共 Enum页面、Service、MQ、报表新旧状态展示、合法迁移、历史数据
MqSer/SyncOrderSer所有下游系统消息字段、路由、重复消息、失败重试
InventorySer采购/销售/退货/盘点/调拨每个交易类型正负方向和实时库存
支付回调采购、活动、账户、退款成功、失败、重复、超时、来源业务

证据与待确认

已确认代码证据:index.php、application/config/routes.php、apis.php、appapis.php、tables.php、application/core/BaseController.php、Controller/Service/Model/Enum/Tasks 目录。

仍需按环境确认:

  • Nginx/OpenResty 到不同入口目录的真实路由和域名。
  • PC session、App 签名、OpenAPI 签名及内部 token 的环境配置。
  • MQ、Redis、ES、Mongo、报表中心在开发/预发/生产的连接和降级策略。
  • 老/新采购、销售服务的数据源和流量灰度开关。
  • getThoroughData() 当前代码中参数过滤变量使用不一致的历史行为是否在运行路径被覆盖。

这些环境项应记录配置名和验证方式,不能在知识库中写入真实密码、密钥或 token。

请求-日志-数据变更追踪卡

多入口请求链路

场景调用方与入口请求载荷/上下文Controller/ConsumerService/Provider汇合点最终业务事实
PC 业务请求浏览器经 index.php 进入 CI 路由session、sid、表单或 JSON、分页参数application/core/BaseController.php 的业务子类对应 application/service 或 application/ServicesModel 与 tables.php 表常量订单、库存或基础资料写入业务库
App/内部接口appapis.php 中的 API code 或 /inner/*API code、用户/门店头、签名上下文、业务参数BaseApiController、Carsteward、OpenAppService 或 controllers/inner/*映射目标 Service与 PC 链路共用业务 Service/Model同一业务表产生等价事实,入口鉴权不同
老 OpenAPI外部系统按 apis.php API code 调用appId、时间戳、签名、外部单号Openapi、OpenService老接口适配层和领域 Service来源单号、sid、内部 billNo外部请求转换为 DGJ 内部订单/状态
MQ/回调/任务支付、订单、配送、OA、商品中心或定时调度destination、routing key、消息体、外部消息号application/controllers/tasks/*Notify.php、*Task.phpMqSer、领域 Service、Provider业务单号与消息业务键异步更新状态、数量或下游同步结果

日志证据矩阵

链路段日志来源可检索锚点成功信号失败信号与下一段关联方式
网关到 PHPWeb 访问日志、CI 请求日志URI、HTTP method、request_id、API code2xx 且进入目标 Controller4xx/5xx、鉴权失败、路由未命中用 request_id 与应用日志关联
Controller目标类和方法、统一异常处理日志Controller 方法、sid、billNo/外部单号参数校验通过并调用 ServiceValidateException、业务异常用业务单号进入 Service 和数据库回查
Service/事务Service 类方法及异常堆栈完整类名、方法名、sid、事务异常commit 后返回业务主键rollback、duplicate、库存/状态校验失败用主键和 transType 查主表、明细、流水
外部调用/MQProvider 请求日志、tasks/*Notify 消费日志destination、routing key、外部单号、支付/OA 单号外部成功码或消费 ACK超时、非成功码、NACK、重复消息用来源单号回到本地关系表和状态字段
静态代码只能确认“应在哪个类和方法找”。具体日志文件名、日志平台索引及是否打印成功日志,必须在目标环境确认;没有日志时以数据库事实和下游回执补证,不能伪造日志文本。

环节数据变更台账

步骤代码位置事务读取事实写入表/缓存/MQ字段或数量变化回查证据
入口归一BaseController、BaseApiController事务外请求参数、session/header、站点上下文请求上下文,不直接写业务表原始参数 -> 标准参数;补入 sid/用户上下文请求日志与 Controller 入参
业务校验Validate/Entry/Enum通常事务外当前状态、类型、权限、数量无或校验缓存非法请求不应产生业务写入错误码、异常堆栈、主表无新增
核心落库领域 Service + Model本地数据库事务内主表、明细、库存/资金当前值业务主表、明细、关系表status: old -> new;数量/金额按动作增减主键、sid、billNo、更新时间、流水
异步副作用MqSer、Provider、Task Consumer与本地事务通常不是同一原子边界已提交的业务事实MQ、缓存、索引、下游系统本地已成功 -> 下游待处理/已处理消息键、消费日志、下游回执、补偿任务

子模块级独立追踪

子模块追踪:pc-request PC 请求生命周期

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
接入解析浏览器经 OpenResty/PHP index.phprequest ID、URI/method、session、form/JSON、sidindex.php -> application/config/routes.php -> application/core/BaseController.php -> 业务 Controllersession 用户、站点、权限、请求参数入口阶段不写业务表;原始请求 -> 标准 Controller 参数access log + request ID + Controller/method + user/sid401/403/404/校验失败零业务写入;先确认环境和路由,不直接改 Service
业务提交Controller 调用领域 Servicerequest ID、sid、业务单号/来源单号application/controllers/scm/*.php -> application/service 或 application/Services -> Model当前状态、主明细、权限和业务前置本地事务 insert/update/delete,状态/数量/金额 old -> new;commit 后响应request ID + business billNo + SQL/影响行数rollback 返回业务错误;响应未知按业务键查 DB,禁止盲目重发

子模块追踪:inner-api Inner 内部 API 生命周期

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
认证解析内部服务调用 /inner/*request ID、内部 token/header、sid/user、JSON、source orderapplication/core/BaseApiController.php -> application/controllers/inner/*调用方身份、站点/用户头、接口权限认证阶段不写业务表;header/body -> 标准上下文URI + request ID + caller/sid + Controller method认证/参数失败零写入;日志脱敏 token,不用生产凭证写文档
领域处理Inner Controller 调 Service/Providerrequest ID、source/internal bill、业务 payloadapplication/controllers/inner/* -> application/Services/*来源唯一性、当前状态和业务数据事务内业务事实 old -> new;外部 HTTP/MQ 在 commit 后异步边界request ID + source/internal bill + external/message ID外部超时先按外部 ID 查询;本地已成只补外部段

子模块追踪:app-gateway App tradeCode 网关

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
映射鉴权App/车管家 tradeCode 请求request ID、tradeCode、签名、用户/设备/sid、paramsapplication/controllers/Carsteward.php -> application/service/OpenAppService.php -> application/config/appapis.phpcode 映射、签名/登录上下文和设备规则网关阶段不写业务表;envelope -> 目标 Service 参数request ID + tradeCode + user/device + mapped class/method无映射/签名失败零写入;先审计缺失映射和兼容响应
执行业务app/pda/service/api 目标方法request ID、tradeCode、业务单号application/service/api/app/* 或 application/controllers/app|pda/* -> 领域 Service当前业务事实和 App 字段口径本地事务 insert/update,业务字段 old -> new;响应保留旧合同tradeCode + request ID + billNoHTTP 200 仍核业务 code;响应未知按业务键回查而非重复调用

子模块追踪:openapi 老 OpenAPI 动态分发

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
鉴权分发外部系统 Openapi 请求request ID、transCode、appId、timestamp/sign、source orderapplication/controllers/Openapi.php -> application/service/OpenService.php -> application/config/apis.phpapp 授权、签名、交易码映射、Redis/Mongo 幂等状态鉴权阶段业务表不写;requestId 状态无 -> processingtransCode + request ID + appId(hash) + source orderE100xx 零业务写入;processing 超时先查 Mongo/业务事实
动态执行映射的 service/api/*request ID、transCode、标准参数、来源单application/service/api/* -> 领域 Service/Model来源唯一性、状态、数量金额事务内业务 old -> new;Mongo 幂等 processing -> success/failrequest ID + transCode + source/internal bill部分成功以业务表为准;补断点并保持旧错误码/响应字段兼容

子模块追踪:mq-consumer MQ 回调与消费者

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
分发Broker destination/eventdestination、routing key、message ID、source billapplication/controllers/tasks/*Notify.php -> event handler消息版本、事件类型、当前业务态、幂等键分发阶段通常不写;有效消息进入单消息事务destination + event + message ID + stable business key未知事件/载荷异常按 Consumer 合同 NACK/告警,不主动 ACK 丢消息
落库 ACKhandler 调领域 Servicesource/internal bill、payment/OA/external IDNotify Controller -> application/Services/* / Model当前状态及是否已达到目标消费事务 old -> new,commit 后 ACK;重复业务键 DB 不变业务键串联 Consumer、表记录和 ACK/NACKcommit 与 ACK 之间不原子;重复投递必须幂等,补偿按业务键不用随机 message ID

子模块追踪:cli-task CLI 与定时任务

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
调度扫描crontab/调度平台执行 CLItask/method、env、batch、time window、cursor/limitapplication/controllers/tasks/*Task.php -> 任务 Service候选状态、更新时间、checkpoint 和环境开关扫描只读;候选集合由查询 -> 固定批次task + batch + start/end + scanned count禁止 Web 运行、无边界全表扫描;异常保留 cursor 续跑
单条执行任务对每个 business IDbatch、business ID、稳定幂等键Task -> application/Services/* / MqSerbefore 状态和外部最终事实每条事务 old -> expected 或重发消息;已完成 DB 不变batch + ID + before/after + success/skip/fail小批重跑;部分失败只重试失败 ID,禁止把成功项再次扣加

子模块追踪:transaction-data 统一事务与数据访问边界

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
本地事务领域 Service 开始写业务事实request ID、sid、billNo、当前版本/statusapplication/Services/* / application/service/* -> Model/BaseModel主表、明细、流水、行锁和分片键同连接事务内 insert/update/delete,主明细/库存/资金 old -> new;异常 rollbackrequest ID + billNo + transaction exception + affected rows确认所有 Model 是否同连接;跨连接写不能假装原子,需独立补偿
事务外副作用commit 后 Provider/MQ/cache/index/reportbillNo、external request/message ID、cache keyapplication/Providers/BaseProvider.php、application/Services/Mq/MqSer.php、Cache Service已提交本地事实本地 DB 不变;外部/缓存/索引 old -> new,最终一致billNo + external/message ID + cache/index version外部成功本地失败/反向情况分段处理;只补失败副作用,不重做主事务