尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

go-zero 微服务里,聚合根到底该怎么落地?

go-zero 微服务里,聚合根到底该怎么落地? go-zero 微服务里聚合根到底该怎么落地【免费下载链接】go-zeroA cloud-native Go microservices framework with cli tool for productivity.项目地址: https://gitcode.com/GitHub_Trending/go/go-zero半夜被叫起来查线上问题订单状态已经推到已支付库存却一分没动对账脚本一跑全是红。翻了半天病根不在 SQL而在你的 go-zero 聚合根没设计对——领域边界根本没划清。这篇就带你把 DDD 聚合根设计在 go-zero 里真正落地少踩坑。先看看不一致都长什么样 症状看着五花八门其实就那几类你都熟悉状态改了关联的量没跟着变A 服务写了一半B 服务还在读旧值两笔并发请求把同一个数改乱了回滚的时候改过的地方回不干净翻来覆去看根子都是一个领域边界没划清谁都能伸手改同一份数据。三个概念一次讲清别被 DDD 吓到就三个东西。拿快递打个比方聚合根就是你打包好的那个包裹唯一追踪号贴在包裹上实体是箱子里带编号的贵重件有自己的生命周期值对象是商品标签、易碎贴纸没有身份只用来比较。怎么判定标准很直接有唯一 ID、是对外唯一入口、跨对象的校验都挂在它身上的就是聚合根有身份、状态会变的是实体没身份、靠属性判等、不可变的是值对象。核心特点记四点背下来就够用唯一标识挂在根上而不是子对象上子对象的生命周期由根托管规则校验集中在根子对象不自己拍板 外部只认根这扇门其余全是内部go-zero 里的聚合根入口读 Aggregate 方法你可能会问一个查数据的方法跟聚合根有啥关系go-zero 在 core/stores/mon/model.go 里用 MongoDB 的 Model 承载聚合落库Aggregate恰恰是一次进出最典型的落库入口// Aggregate executes an aggregation pipeline. func (m *Model) Aggregate(ctx context.Context, v, pipeline any, opts ...options.Lister[options.AggregateOptions]) error { cur, err : m.Collection.Aggregate(ctx, pipeline, opts...) if err ! nil { return err } defer cur.Close(ctx) return cur.All(ctx, v) }三个点值得咂摸原子性整条 pipeline 当一个整体执行cur.All一把取回再配合 Session / WithTransaction 就是跨文档的事务边界——这正是聚合根要么整单成、要么整单滚在存储层的投影泛型类型安全v和pipeline都是any但出口统一走error结果反序列化进你的领域结构类型始终攥在你手里ctx 全程透传底层 core/stores/mon/collection.go 里startSpan/endSpan打点、brk.DoWithAcceptableCtx走熔断超时、追踪、熔断全靠这条 ctx 串起来重构前后让聚合根管住数据先看反例绕过校验直接改子表// 反例绕过根直接 UPDATE 子表 func (r *itemRepo) UpdateQty(itemID, qty int) error { _, err : r.db.ExecContext(ctx, UPDATE order_item SET quantity? WHERE id?, qty, itemID) return err }正例是把校验收进根里落库也走根这一个入口// 正例校验集中在根落库走事务整单提交 func (o *Order) AddItem(p Product, qty int) error { if o.Status ! StatusPending || qty 0 { return ErrNotAllowed } o.Items append(o.Items, OrderItem{P: p, Qty: qty}) return nil } func (repo *orderRepo) Save(ctx context.Context, o *Order) error { _, err : repo.sess.WithTransaction(ctx, func(sessCtx context.Context) (any, error) { return nil, repo.update(sessCtx, o) }, nil) return err }整单进出客户端永远摸不到 OrderItem避坑清单照着打勾✅ 几条最容易踩的对着你的代码过一遍要点说明典型反例特征边界对应业务闭环一个根管一段完整业务订单、支付、库存塞进同一个根根是唯一入口外部只进根出现直接 UPDATE 子表的代码控制聚合大小根别太胖一个根挂着十几个子实体校验集中在根规则不分散实体自己判断状态根不管值对象保持不可变只比较不修改值对象被原地改字段想继续往下走仓库里有现成的路标验证并发下的聚合行为看 core/stores/mon/collection_test.go 里对 cursor 与 pipeline 的 mock做跨服务强一致参考 core/stores/redis/redislock.go 基于 Lua 的分布式锁玩事件溯源风格的聚合从 core/stores/mon/model.go 的 Session / WithTransaction 入手 现在就挑你那个改了状态、库存不动的模块把所有子表操作收敛进一个根里。【免费下载链接】go-zeroA cloud-native Go microservices framework with cli tool for productivity.项目地址: https://gitcode.com/GitHub_Trending/go/go-zero创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表