导语:在上一篇文章中,我分享了项目从“暗黑风”到“绿色温情”的重构之路。后台有朋友问我,这样一个涵盖了社区互换、平台回收、商家兑换的复杂平台,底层数据是怎么打通的?今天这篇,就来硬核拆解一下我的数据库设计思路。
如果只是做个简单的二手交易平台,其实几张表就搞定了:用户表、商品表、订单表。
但「闲物焕新」的核心不仅是“卖”,而是“物-积分-服务”的双向流转。用户可以把物品交给平台换积分,积分可以去商家那里换服务。这就意味着,系统里不仅要有“物品订单”,还得有“回收单”、“核销单”、“积分流水”等。
为了支撑这套生态,我的 MySQL 数据库最终扩展到了 34 张表。按领域切分,可以分为五大阵营:用户鉴权、物品流转、回收与交易、商家生态、以及 AI 监控。
一、 万物皆可流转:物品表(item)的深度定制
系统架构图
物品是平台的核心实体。传统的电商物品表很简单,但在我们这里,它被赋予了更多使命:
1. 状态机的精准流转
物品不是一直处于“在售”状态的。我设计了严格的状态机:
4 = 待审核(用户发布后默认)
1 = 已上架(管理员审核通过)
3 = 被驳回(需附带理由)
2 = 已下架/已换出
这个状态机不仅是给前端看的,更关键的是在 4 -> 1 审核通过的那一瞬间,系统会在同一个数据库事务内,自动触发积分发放和碳减排数据的写入。
2. 兼容 AI 的扩展字段
平台接入了多模态大模型,所以物品表必须留有 AI 的“痕迹”。比如 ai_tags 存大模型提取的标签,condition_level 存成色评估。最核心的是,我预留了 panorama_views 和 model_status,用于追踪 3D 模型和 360° 视图的异步生成状态。
3. 隐私与 LBS 的博弈
为了支持“离我最近”的匹配,我需要计算坐标距离。但我深知隐私的重要性:在 SQL 查询层,我直接加上了限制条件——未开启位置公开的用户,其物品坐标绝不出现在检索结果中(从数据源头上断掉泄露风险)。
二、 踩坑实录:不用 Celery,我用 BackgroundTasks 生成 3D 模型
在物品发布和展示时,我们接入了腾讯混元 3D 模型。大家知道,3D 渲染是非常耗时的(平均90多秒),如果让前端同步等待,页面肯定直接崩了。
像上一篇文章里我提到“不用 Redis 实现了验证码”一样,这次我也没去引入厚重的消息队列(如 Celery/RabbitMQ),而是直接利用了 FastAPI 自带的 BackgroundTasks。
当用户触发 3D 生成,后端直接返回 generating 状态给前端。
后台任务悄悄去调混元 API,下载 GLB 文件并做魔数校验(Magic Number),防止接口抽风拿回一个损坏文件导致前端白屏。
前端通过定时轮询 model_status 即可获取最新进度。
这套轻量级的异步方案,不仅解耦了 HTTP 请求,还避免了在演示环境里维护复杂消息队列的麻烦。
三、 并发防护:交易系统的生死线
做交易系统,最怕的就是“被薅羊毛”和“数据错乱”。我在这块设下了两道铁闸:
防重复发积分(唯一索引):在 points_log 表建立了一个由 source(业务类型)、related_id(关联订单)、user_id 组成的唯一索引。无论因为什么并发 bug 导致代码被多调了一次,数据库层面直接拦截,保证一笔业务只发一次积分。
防重复核销(条件更新):商家核销兑换码时,SQL 语句必须是 UPDATE ... WHERE status = 1,如果 rowcount 为 0,说明已经被核销过了,直接拒绝。
四、 下一期预告
物品表和数据库是整个平台的骨架。那么,有了数据,怎么让 AI 真正“动”起来,去理解用户、调用真实接口呢?
下一篇,我会分享这个平台的核心大脑:【基于 Function-Calling 与 MCP 协议的单智能体架构实战】,带大家看看我是如何让大模型告别“只会聊天”,真正能查周边物品、画统计图表的。敬请期待!