邀请码表须用char(16)存随机码,含code(唯一索引)、inviter_id、used_at、expires_at(默认7天)、created_at;校验注册需原子UPDATE,生成用6位base36去重防混淆,关系链应预计算存辅助表。

邀请码表设计必须带有效期和使用状态
直接用 CHAR(16) 存邀请码,别用自增ID当邀请码——容易被枚举。字段至少包含:code(唯一索引)、inviter_id(发码用户ID)、used_at(NULL表示未用)、expires_at(DATETIME,建议默认 7 天后)、created_at。避免把邀请关系硬编码进用户表,否则后期查谁邀请了谁、统计邀请数会非常慢。
注册时校验邀请码要原子性更新
不能先 select 再 UPDATE,否则并发注册可能让同一码被多人成功使用。必须用单条语句完成校验+标记已用:
UPDATE invite_codes SET used_at = NOW(), user_id = ? WHERE code = ? AND used_at IS NULL AND expires_at > NOW();
执行后检查 ROW_COUNT() 是否为 1。返回 0 表示码无效(过期/已用/不存在),不是程序错误,而是业务规则拦截。
生成邀请码别用 UUID 或时间戳拼接
UUID 太长且可读性差;时间戳易预测。推荐用「随机字符串 + 校验位」组合:
- 用
RAND()配合CONV(FLOOR(RAND()*POW(36,6)),10,36)生成 6 位 base36 字符串(约 20 亿种组合) - 插入前加
UNIQUE KEY(code)约束,冲突则重试(一般 1–2 次就成功) - 避免字母
O和数字0、I和1混淆,生成时过滤掉
邀请关系链不要靠递归查询实现
mysql 8.0 虽支持 CTE 递归,但深度稍大(比如邀请 5 层以上)就会慢甚至超时。实际项目中,如果需要统计“某用户带来的全部下线”,应该在注册时就写死一级关系,并用定时任务或触发器维护一个 user_ancestors 辅助表,存 user_id 和其所有上级 inviter_id 及层级。否则每次查都要 WITH RECURSIVE,线上扛不住。