mysql实现简易用户反馈与意见收集系统

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

为什么不用现成表单服务而选 MySQL 自建

因为需要和已有用户体系(比如

users
表)做关联,或要嵌入后台管理页直接查、导出、打标签,又或者反馈内容要参与后续的 SQL 统计(如按部门/版本号/问题类型聚合)。用第三方表单服务反而增加权限、字段映射、数据同步成本。

feedback
表结构怎么设计才够用又不冗余

核心是平衡扩展性与查询效率。别一上来就加 JSON 字段存所有元信息——后期没法索引、难统计。推荐用固定字段 + 可选扩展字段组合:

CREATE TABLE `feedback` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` INT UNSIGNED NULL COMMENT '关联 users.id,匿名提交可为 NULL',
  `email` VARCHAR(255) NULL COMMENT '非必填,但留着方便回访',
  `title` VARCHAR(120) NOT NULL COMMENT '一句话概括问题',
  `content` TEXT NOT NULL COMMENT '详细描述,支持换行',
  `category` ENUM('bug', 'feature', 'ui', 'performance', 'other') DEFAULT 'other',
  `status` ENUM('pending', 'reviewed', 'replied', 'closed') DEFAULT 'pending',
  `ip` VARCHAR(45) NULL COMMENT 'IPv4/IPv6,用于简单去重或风控',
  `ua` TEXT NULL COMMENT '只存前 200 字,足够识别设备+浏览器',
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_category_status` (`category`, `status`),
  KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
user_id
允许为 NULL,兼容未登录用户提交
category
ENUM
而不是外键,避免小表 JOIN,且变更成本低;后期想加新类型,用
ALTER TABLE ... MODIFY category ENUM(...)
即可
ip
VARCHAR(45)
足够存 IPv6,别用
INT
BINARY(16)
——除非你真要跑 GEOIP 查询,否则纯属过早优化
没加
fulltext
索引:普通
LIKE '%关键词%'
content
就够用;真要全文检索再单独上
MyISAM
或切到 Elasticsearch

后端插入时怎么防重复提交和基础校验

光靠前端限制没用。MySQL 层面至少要做两件事:唯一约束 + 时间窗口限流。

对匿名用户,用
(ip, ua, created_at > NOW() - INTERVAL 10 MINUTE)
做应用层判断(查完再插),MySQL 本身不支持动态时间范围的唯一索引
对已登录用户,加唯一约束:
ALTER TABLE feedback ADD UNIQUE KEY uk_user_id_created (user_id, created_at);
,配合应用层控制「同一用户 5 分钟内只能提一条」
content
字段入库前必须
TRIM()
并检查长度,MySQL 默认会截断超长
TEXT
,但最好在应用层抛错,避免静默失败
别把
ua
全量存——用
LEFT(ua, 200)
截取,防止超长 UA 导致插入失败或拖慢写入

查反馈时怎么兼顾效率和灵活性

运营或客服查数据,最常问的是「今天收到多少 bug?」「上周未回复的有哪些?」「某个邮箱发了几条?」。这些查询必须走索引,不能全表扫。

SELECT COUNT(*) FROM feedback WHERE status = 'pending' AND created_at >= '2024-06-01';
—— 靠
idx_category_status
idx_created_at
覆盖
SELECT * FROM feedback WHERE email = 'a@b.com' ORDER BY created_at DESC LIMIT 20;
—— 需要给
email
加索引:
ALTER TABLE feedback ADD INDEX idx_email (email);
避免
SELECT * FROM feedback WHERE content LIKE '%卡死%';
,这种必然慢;真要模糊搜,用
SELECT ... WHERE MATCH(content) AGAINST('卡死' IN NATURAL LANGUAGE MODE)
(需先加 FULLTEXT 索引)
导出全部数据时,别用
SELECT * FROM feedback
—— 加
WHERE id > ? ORDER BY id LIMIT 1000
分页拉取,防止大结果集撑爆内存或连接超时

字段加多了容易,删掉或改类型就麻烦。上线前先按「未来三个月肯定要查的维度」建好索引,别等慢了再补。

相关推荐