设备资产管理系统三大卡点:唯一标识需用asset_id+source_type联合主键并显式建索引;变更日志须同时存快照与diff;软删除应改用status字段替代deleted_at,避免报表漏项。

设备资产管理系统上线卡点,90% 不是功能没写完,而是唯一标识混乱、变更日志丢数据、软删除导致报表漏项——这三个硬伤不提前堵住,后期改库+补日志的成本远超重写。
asset_id + source_type 联合主键必须显式建索引
设备跨云/跨系统接入时,单靠 asset_id 无法保证全局唯一。比如阿里云 ECS 的 i-xxx 和 AWS EC2 的 i-xxx 冲突,但加上 source_type(值为 "aliyun" 或 "aws")就能区分。
-
source_type字段必须设为非空字符串,不能用空值或"unknown"占位,否则联合索引失效 - GORM 迁移时别依赖自动建表,手写
db.Exec("CREATE UNIQUE INDEX idx_asset_source ON assets (source_type, asset_id)") - 查询时永远用
db.Where("source_type = ? AND asset_id = ?", "aliyun", "i-12345").First(&asset),不用db.First(&asset, "i-12345")
变更日志必须存快照 + diff,不能只记字段名
审计要求查“谁在什么时间把服务器的 status 从 running 改成 stopped”,只存 {"field": "status", "old": "running", "new": "stopped"} 够用;但若要回滚或比对历史状态,就得存完整 JSON 快照。
- 日志表字段至少含:
asset_source_type、asset_source_id、snapshot(TEXT)、diff(JSON,含变更字段名、旧值、新值)、operator_id、created_at - 生成
diff别手写字符串拼接,用jsondiff库(如github.com/wI2L/jsondiff),它能处理嵌套结构和类型变化 - 快照字段
snapshot存的是变更前的完整资产结构体序列化结果,不是当前最新状态——否则日志和实际数据不同步
status 字段替代 deleted_at,避免 GORM 自动过滤
用 deleted_at 做软删除,GORM 默认所有 Find() 都加 WHERE deleted_at IS NULL,结果后台导出报表时漏掉已报废设备,财务对不上账。
- 直接删掉
deleted_at字段,换成statusstring 类型,取值限定为"active"、"retired"、"transferred"、"scraped" - 全局查询加
WHERE status IN ('active', 'retired'),而不是依赖 GORM 隐式行为 - 前端“回收站”页面查
status = 'scraped',恢复操作只是 UPDATE status,不是 Unscoped() + Save()
真正难的不是写接口,是让每条资产记录从入库那一刻起,就带着可追溯的上下文:谁建的、从哪来、改过几次、每次改了什么——这些信息一旦漏掉,后面补的成本是实时写入成本的十倍以上。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











