【Webman+MySQL答题系统三】数据库表结构与初始化脚本
果子发表于:2026-10-05 20:55:42浏览:1次
本篇目标
把第一篇设计的 6 张表落成 SQL:加索引、灌初始数据,并约定脚本的管理方式。

一、建表脚本
保存为 database/init.sql,整体执行(MySQL 5.7+,utf8mb4 + InnoDB):
USE quiz_system;
CREATE TABLE `user` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录名',
`password` varchar(100) NOT NULL COMMENT '密码哈希',
`nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
CREATE TABLE `question` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`type` tinyint NOT NULL DEFAULT 1 COMMENT '1单选 2多选 3判断',
`title` varchar(500) NOT NULL COMMENT '题干',
`options` json NOT NULL COMMENT '选项,如 {"A":"...","B":"..."}',
`answer` varchar(20) NOT NULL COMMENT '标准答案,逗号分隔',
`analysis` varchar(500) NOT NULL DEFAULT '' COMMENT '解析',
`score` decimal(5,1) NOT NULL DEFAULT '2.0' COMMENT '默认分值',
`status` tinyint NOT NULL DEFAULT 1,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='题库表';
CREATE TABLE `paper` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`total_score` decimal(6,1) NOT NULL DEFAULT '0' COMMENT '总分',
`pass_score` decimal(6,1) NOT NULL DEFAULT '60' COMMENT '及格线',
`duration` int NOT NULL DEFAULT 60 COMMENT '时长(分钟)',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '1启用 0停用',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='试卷表';
CREATE TABLE `paper_question` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`paper_id` int unsigned NOT NULL,
`question_id` int unsigned NOT NULL,
`sort` int NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_paper_question` (`paper_id`,`question_id`),
KEY `idx_question` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='试卷题目关联表';
CREATE TABLE `record` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`paper_id` int unsigned NOT NULL,
`user_id` int unsigned NOT NULL,
`score` decimal(6,1) NOT NULL DEFAULT '0',
`is_pass` tinyint NOT NULL DEFAULT 0,
`use_seconds` int NOT NULL DEFAULT 0,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user` (`user_id`),
KEY `idx_paper_user` (`paper_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='答题记录表';
CREATE TABLE `record_answer` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`record_id` int unsigned NOT NULL,
`question_id` int unsigned NOT NULL,
`answer` varchar(50) NOT NULL DEFAULT '' COMMENT '用户答案',
`is_right` tinyint NOT NULL DEFAULT 0,
`get_score` decimal(5,1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_record` (`record_id`),
KEY `idx_question` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='答题明细表';
索引设计说明:uk_paper_question 防止同一题重复入卷;record.idx_paper_user 服务"某人某卷的成绩"高频查询;record_answer.idx_question 服务错题聚合。
二、表关系图

paper_question 是典型多对多中间表:一道题可以同时出现在多份卷里,改题一处生效。中间表没有业务主键,靠组合唯一键约束。
三、初始化数据
INSERT INTO `question`(`type`,`title`,`options`,`answer`,`analysis`,`score`) VALUES
(1,'Webman 是基于哪个项目构建的?','{"A":"Symfony","B":"Workerman","C":"ReactPHP","D":"Swoole"}','B','Webman 以 workerman 为内核,保留常驻内存特性。',2),
(2,'下列哪些属于 PHP 常驻内存运行方式?','{"A":"Webman","B":"PHP-FPM 传统模式","C":"Swoole 系框架","D":"Laravel Octane"}','A,C,D','',3),
(3,'Webman 默认监听端口是 8787。','{"A":"对","B":"错"}','A','',1);
INSERT INTO `paper`(`title`,`total_score`,`pass_score`,`duration`) VALUES
('Webman 基础测试卷', 6, 4, 30);
INSERT INTO `paper_question`(`paper_id`,`question_id`,`sort`) VALUES
(1,1,1),(1,2,2),(1,3,3);
用户表密码存哈希,不要手写明文。先生成一个:
php -r "echo password_hash('123456', PASSWORD_DEFAULT);"
把输出粘进去:
INSERT INTO `user`(`username`,`password`,`nickname`) VALUES
('zhangsan', '粘贴上面的哈希', '张三');
四、执行方式
- 命令行:
mysql -uroot -p quiz_system < database/init.sql; - 或 Navicat 里直接运行 SQL 文件;
- init.sql 纳入 Git 版本管理,结构变更走 ALTER 脚本(init_02.sql、init_03.sql 递增),不要回头改老文件——这是多人协作时唯一能追溯历史的方式。
小结
表结构、索引、种子数据全部就位。下一篇开始写业务代码:题目管理的增删改查接口。
栏目分类全部>

