如何实现短信验证码存储_mysql验证码表设计

来源:这里教程网 时间:2026-02-28 20:38:12 作者:

短信验证码通常需要短期存储、高频读写、自动过期,MySQL 表设计要兼顾安全性、查询效率和清理便利性。核心原则是:字段精简、索引合理、过期机制明确、避免明文存验证码(尤其生产环境)。

基础表结构设计(含关键字段)

以下是一个推荐的

sms_verify_code
表结构:

id:BIGINT UNSIGNED AUTO_INCREMENT,主键,便于分页或日志追踪(非必须但建议) phone:VARCHAR(16),标准化手机号(如 +8613912345678 或 13912345678),不加索引前需统一格式 code:CHAR(6) 或 VARCHAR(10),存实际验证码(测试/开发可明文;生产建议加密存储或仅存哈希) send_at:DATETIME(3) 或 TIMESTAMP(3),精确到毫秒,记录发送时间(用于计算有效期) used:TINYINT(1) DEFAULT 0,标记是否已被验证使用(防止重放) ip:VARCHAR(45),可选,记录请求IP,辅助风控 scene:VARCHAR(20),可选,标识用途(如 "login", "register", "reset_pwd"),方便多业务复用

必须添加的索引策略

没有合适索引,查验证码会变慢甚至拖垮数据库:

联合索引 (phone, used, send_at):覆盖最常用查询 —— “查该手机号未使用且未过期的最新码” 单独索引 (send_at):支撑定时任务快速找出所有过期记录(例如:WHERE send_at 避免对
code
建索引 —— 无业务意义,还增加写开销

安全与生产注意事项

直接存明文验证码在 MySQL 中存在风险,尤其当数据库被脱库时:

开发/测试环境可暂存明文,但上线前必须改 生产环境建议:存储 code 的 SHA-256 哈希值(如
SHA2(CONCAT(code, salt, phone), 256)
),验证时对用户输入做同样哈希比对
限制单手机号单位时间内的发送频次(应用层+缓存层控制,如 Redis 计数),MySQL 表不承担限流职责 验证码有效期统一设为 5 分钟,数据库不存 expire_at 字段,用
send_at + INTERVAL 5 MINUTE
动态计算,省空间且不易出错

配套清理机制(别只建表不清理)

验证码表会持续增长,必须定期归档或清理:

每日凌晨执行:DELETE FROM sms_verify_code WHERE send_at 保留已使用记录 24 小时,便于审计;未使用超时记录可更早清理(如 30 分钟后) 大表场景下,考虑按月分区(如按 send_at RANGE 分区),提升删除效率

相关推荐