news 2026/9/26 5:55:13

MySQL实战:从零搭建学生选课库,搞定建库建表与存储过程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL实战:从零搭建学生选课库,搞定建库建表与存储过程

1. 第一次MySQL作业:从零搭一个学生选课库

前几天部门来了个实习生,我给他布置了入职后的第一个正式任务:在一台全新的Linux服务器上,从安装MySQL开始,到建库建表、写增删改查、再搞一个存储过程,最后交一份完整的选课系统数据库出来。这个任务听起来简单,但真正走一遍会发现,坑全埋在细节里——比如socket连不上、UPDATE语法写错、存储过程里的分号导致报错,每一个都能把人卡住半天。

这篇文章就把这份“MySQL第一次作业”的完整过程拆给你看。不管你是刚入行的开发新人,还是准备带新人的老手,照着这个流程走一遍,MySQL的日常操作基本就过关了。文中涉及的所有命令和SQL,我都标注了版本和适用环境,用的是MySQL 8.0版本,操作系统为CentOS 7以上的Linux发行版。如果你用的是Windows或macOS,安装部分我会额外说明差异。

作业目标我设成了这样:做一个简化版的学校选课系统,包含学生表、课程表、选课记录表三张核心表,要求完成建库、建表、插入数据、按条件查询、修改数据、删除数据、编写存储过程,并且全程记录遇到的问题和解决方法。这个范围刚好覆盖了MySQL最常用、面试最容易问到的知识点。

先看整体流程,总共分六个阶段:安装MySQL、连接与建库、建表与约束设计、增删改查、存储过程、问题排查。下面我按实际操作的顺序一步步来讲。

2. 安装这一步:为什么推荐官网Yum仓库而不是sudo apt

很多新手装MySQL习惯直接sudo apt install mysql-server,然后在Debian系机器上装完发现连mysqld都找不到,或者装了个MariaDB的兼容分支,版本和官方不一致,后面做JSON字段、窗口函数时各种报错。我第一次带人做作业就吃了这个亏,所以我现在的建议是:一律从官方仓库装,或者用Docker起官方镜像,二选一,别用发行版自带的。

CentOS/RHEL系统官方推荐的安装方式是先加MySQL官方Yum仓库:

# 下载并安装MySQL官方仓库rpm包 wget https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm yum localinstall mysql80-community-release-el7-7.noarch.rpm -y # 安装MySQL社区版服务端 yum install mysql-community-server -y # 初始化并启动服务 systemctl start mysqld systemctl enable mysqld

装完之后第一件事是找临时密码:

grep 'temporary password' /var/log/mysqld.log

这个临时密码是MySQL 8.0安全策略的一部分,首次登录会让你强制修改。登录命令是:

mysql -uroot -p

输入上面日志里查到的临时密码,进入MySQL后立刻执行:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Your_Strong_Password_2025';

注意这里密码必须够强,MySQL 8.0默认开了validate_password组件,要求至少8位且包含大小写字母、数字和特殊字符。如果不想这么麻烦,可以临时降低密码策略再改回:

SET GLOBAL validate_password.policy = LOW; SET GLOBAL validate_password.length = 6; ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'; SET GLOBAL validate_password.policy = MEDIUM;

如果你用的是Docker,那就更省事,一条命令拉起来:

docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=school \ mysql:8.0

这里要提醒一个常见坑:Docker方式启动时,容器内部的MySQL默认只监听localhost,如果外部客户端连不上,大概率是因为没有指定--network=host或者没做端口映射。上面命令里我写了-p 3306:3306,这一步不能省。另外数据持久化一定要挂载数据卷,否则容器一删数据全没了:

docker run -d --name mysql8 \ -p 3306:3306 \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0

安装完成后顺手验证一下版本:

SELECT VERSION();

输出应该是8.0.x,到了这一步,环境就算是准备好了。

3. 第一次连上MySQL:你能遇到的最典型的三个“连不上”

作业做完环境搭建,接下来要面对的坑几乎都集中在“连不上”这三个字上。我总结了一下我带人过程中见过最高频的三种情况,每种我都附了排查思路,你照着做就行,这些错误在热搜词里也出现了好几个。

3.1 Error 2002: Can't connect through socket

新手执行mysql -uroot -p时看到下面这行报错会特别懵:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

这句话翻译过来就是:MySQL客户端想通过/tmp/mysql.sock这个本地socket文件连到服务端,但找不到这个文件。(2)表示文件不存在,错误码2在Linux里对应ENOENT。出现这个报错通常是两个原因:一是MySQL服务根本没启动,二是socket文件路径不对。

先排除第一个原因:

systemctl status mysqld

如果服务没启动,直接:

systemctl start mysqld

再登录一次就好了。如果服务已经启动了还是报socket不存在,那就用TCP方式连一次试试:

mysql -uroot -p -h127.0.0.1 -P3306

用-h127.0.0.1时客户端会走TCP协议而不是socket文件。如果能连上,说明socket路径配置和生产不一致,修改/etc/my.cnf里的socket行即可。如果TCP也连不上,检查端口:

ss -lntp | grep 3306

没有输出说明mysqld根本没监听3306,八成是配置文件的bind-address设置问题。

3.2 Navicat连接报错:密码插件不兼容

服务器上mysql -uroot -p能进,本地Navicat却连不上,这是第二个高频问题。MySQL 8.0默认的认证插件是caching_sha2_password,而老版本Navicat(12.0以下)只支持mysql_native_password,两边对不上自然连不上。

解决方式有两种。第一种是改用户的认证插件:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

第二种更推荐——升级Navicat到16以上版本,全系列都支持caching_sha2_password了。

3.3 JDBC连接报SSL错误

如果作业里要求写Java程序连MySQL,你大概率会看到下面这行报错:

java.sql.SQLException: SSL connection error: java.net.SocketException: Broken pipe

MySQL 8.0默认开启SSL,但自签名证书在JDBC中的校验经常出问题。对作业场景来说,直接在JDBC连接串后面加useSSL=false就能绕过去:

jdbc:mysql://127.0.0.1:3306/school?useSSL=false&serverTimezone=Asia/Shanghai

如果你确实想用SSL连接,需要把CA证书导入Java信任库,步骤比较繁琐,作业阶段不建议碰。当然生产环境SSL是必开的,我的意思是别在第一次作业上死磕这个,先保证程序能跑通。

4. 建库建表:类型选错是后面所有麻烦的起点

连上MySQL之后,正式开始做作业里的核心部分。先建库:

CREATE DATABASE IF NOT EXISTS school DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;

utf8mb4比utf8多支持四字节的Emoji字符和生僻字,现在的MySQL项目我基本全部用utf8mb4,不要在作业阶段为了省空间用utf8mb3或latin1。排序规则选utf8mb4_general_ci就够了,追求精确排序可以用utf8mb4_unicode_ci,但对选课系统这个场景来说没差别。

接下来建三张表。学生表:

CREATE TABLE student ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '学号', name VARCHAR(50) NOT NULL COMMENT '姓名', gender ENUM('M','F') DEFAULT 'M' COMMENT '性别', birth_date DATE COMMENT '出生日期', phone VARCHAR(20) COMMENT '手机号码', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) ENGINE=InnoDB COMMENT='学生表';

课程表:

CREATE TABLE course ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '课程编号', course_name VARCHAR(100) NOT NULL COMMENT '课程名称', credit DECIMAL(3,1) DEFAULT 2.0 COMMENT '学分', teacher_name VARCHAR(50) COMMENT '授课教师' ) ENGINE=InnoDB COMMENT='课程表';

选课记录表:

CREATE TABLE student_course ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT '学生ID', course_id INT NOT NULL COMMENT '课程ID', score DECIMAL(5,2) DEFAULT 0 COMMENT '成绩,默认0', selected_at DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_sc_student FOREIGN KEY (student_id) REFERENCES student(id), CONSTRAINT fk_sc_course FOREIGN KEY (course_id) REFERENCES course(id), UNIQUE KEY uk_student_course (student_id, course_id) ) ENGINE=InnoDB COMMENT='选课记录表';

这里有几个关键设计点值得说明:

  • score字段我特意设置了默认值0,对应热搜词里的“mysql设置默认值为0”。选课之后成绩还没出,先存0是合理的业务建模,以后查“选了课但没成绩”的学生就是WHERE score = 0。
  • 外键约束FOREIGN KEY在作业里必须有,面试官问“为什么用外键”的时候,标准回答是保证数据完整性,防止插入一个不存在的学生ID。同时也要知道外键对写入性能有影响,生产环境大表往往不用物理外键,靠应用层或定时任务保证,这是个加分的延伸知识。
  • student_id + course_id加了唯一键,业务含义是“一个学生同一门课只能选一次”,这个约束如果漏了,后面写插入语句时就会出现重复选课数据。

表结构建好后,验证一下:

SHOW CREATE TABLE student\G; DESC student_course;

把输出截图存进作业文档里,这步能帮你确认每张表的字段类型、默认值、约束是否符合预期。我第一次带人时,他建完表直接开始插入数据,结果插到一半发现course表里少了个字段,又得删表重建,前面的数据全白费了。建表之后先验证结构,再动数据。

5. 插入数据与UPDATE语法:踩坑最多的地方

结构没问题,接下来造数据。给三张表各插几条:

INSERT INTO student (name, gender, birth_date, phone) VALUES ('张三', 'M', '2000-01-15', '13800000001'), ('李四', 'F', '2001-06-20', '13800000002'), ('王五', 'M', '2002-03-12', '13800000003'); INSERT INTO course (course_name, credit, teacher_name) VALUES ('高等数学', 5.0, '陈老师'), ('大学英语', 3.0, '刘老师'), ('数据库原理', 4.0, '赵老师'); INSERT INTO student_course (student_id, course_id, score) VALUES (1, 1, 85.5), (1, 2, 0), (2, 1, 92.0), (2, 3, 76.5), (3, 2, 0);

注意第二条选课记录和最后一条的score故意保持0,为的是后面演示“查询未出成绩的学生”这个场景。

然后进入作业里最容易出错的部分:UPDATE语法。先看正确写法:

-- 把张三的数据库成绩改成88 UPDATE student_course SET score = 88 WHERE student_id = 1 AND course_id = 3; -- 把李四的英语成绩赋值为默认值 -- 注意这里没有WHERE,会更新所有行,作业里一般不会这么玩 UPDATE student_course SET score = DEFAULT;

新手最常见的错误有两个。第一个是忘记写WHERE,直接把整张表的成绩全改了,等发现的时候已经晚了。第二个是微软风格写法UPDATE student_course SET score = 88, student_id = 1 WHERE course_id = 3这种,在MySQL中完全合法但会把student_id错改。要避免这类问题,就一个习惯:写UPDATE先写WHERE,再写SET。这个习惯我在生产环境也一直用,改数据前先跑一遍SELECT确认影响行数,再执行UPDATE。

我刚才建表时把score默认值设成0,可以用在查询里:

-- 找出所有选了课但还没有成绩的学生 SELECT s.name, c.course_name FROM student s JOIN student_course sc ON s.id = sc.student_id JOIN course c ON c.id = sc.course_id WHERE sc.score = 0;

这条JOIN查询就是作业里的核心考点之一了,三表关联查,每一行都要说清楚为什么用JOIN而不是子查询。JOIN在MySQL里优化的空间更大,数据量大时通常比逐行子查询快。

6. 排序、日期处理与存储过程:作业里最见功力的部分

6.1 ORDER BY与字符串转日期

排序是MySQL的入门高频点。按成绩从高到低排:

SELECT s.name, c.course_name, sc.score FROM student s JOIN student_course sc ON s.id = sc.student_id JOIN course c ON c.id = sc.course_id ORDER BY sc.score DESC;

如果要查某门课成绩排名前二的学生,加个LIMIT 2。面试喜欢问“ORDER BY到底按什么规则排序”,其实默认升序ASC,字符按排序规则的二进制比较,数值按数值大小,NULL总是排在最前面(升序时)。

日期处理这块也是热搜词里高频项。假设作业给的数据里日期是字符串格式'2025-01-15',要转成日期类型才能和birth_date比较,可以用:

-- 字符串转日期 SELECT STR_TO_DATE('2025-01-15', '%Y-%m-%d'); -- 日期转字符串 SELECT DATE_FORMAT(birth_date, '%Y年%m月%d日') FROM student; -- 年龄计算 SELECT name, TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age FROM student;

STR_TO_DATE和DATE_FORMAT是两个方向相反的函数,一个是字符串进、日期出,一个是日期进、字符串出。第一次写的人经常会搞混参数顺序,我见过好几个新手把格式化字符串放在前面导致查不出数据。记住:STR_TO_DATE(字符串, 格式)是去解析字符串,DATE_FORMAT(日期, 格式)是去格式化日期。

6.2 存储过程:分号处理是核心

存储过程是这份作业的压轴任务,代码本身倒不难,难的是理解MySQL客户端的分号分隔规则。先看这段代码:

DELIMITER $$ CREATE PROCEDURE sp_add_score( IN p_student_id BIGINT, IN p_course_id INT, IN p_score DECIMAL(5,2) ) BEGIN DECLARE v_exists INT DEFAULT 0; SELECT COUNT(*) INTO v_exists FROM student_course WHERE student_id = p_student_id AND course_id = p_course_id; IF v_exists = 0 THEN INSERT INTO student_course (student_id, course_id, score) VALUES (p_student_id, p_course_id, p_score); ELSE UPDATE student_course SET score = p_score WHERE student_id = p_student_id AND course_id = p_course_id; END IF; END$$ DELIMITER ;

重点在第1行和第19行。MySQL客户端默认把;当作一条语句结束的标记,而存储过程体内部有很多分号,如果不把分隔符临时改成$$,客户端会在DECLARE那行就截断过程体,然后报一堆语法错误。这个DELIMITER就是热搜词里“mysql中触发器中分隔符”指的核心点,写触发器、存储过程、事件调度器时全都绕不开。

写完存储过程后调用:

CALL sp_add_score(3, 1, 66.5);

然后查一下:

SELECT * FROM student_course WHERE student_id = 3;

如果用DBeaver或Navicat这类GUI工具,存储过程体里的分号不需要手动改分隔符,工具内部会处理。但命令行模式下不改DELIMITER一定报错,这个区别值得在作业总结里写一笔,能体现你真正实践过。

6.3 存储过程中的错误处理

作业进阶一点,可以在存储过程里加异常处理。比如成绩不在0到100之间就抛个错误:

DELIMITER $$ CREATE PROCEDURE sp_add_score_safe( IN p_student_id BIGINT, IN p_course_id INT, IN p_score DECIMAL(5,2) ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '成绩无效或插入失败'; END; START TRANSACTION; IF p_score < 0 OR p_score > 100 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '成绩必须在0-100之间'; END IF; INSERT INTO student_course (student_id, course_id, score) VALUES (p_student_id, p_course_id, p_score) ON DUPLICATE KEY UPDATE score = p_score; COMMIT; END$$ DELIMITER ;

这里用到了三个新知识点:DECLARE EXIT HANDLER声明异常处理器,SIGNAL主动抛出错误,ON DUPLICATE KEY UPDATE处理唯一键冲突。如果你第一次接触这些概念,建议把上面这段逐行读明白,它能覆盖MySQL面试题里存储过程相关的六成题型。

从“三建”到“一过程”,作业的数据操作部分就完整了。到这里已经能交一份很体面的作业了,但既然说了要做一个好project,下面的性能优化是加分项。

7. 作业提交前的自查:索引与SQL调优

作业要拿高分,只把功能跑通是不够的。我让每个新人在提交前都做一遍自查,查三件事:索引、执行计划、死锁处理。

7.1 索引:什么时候该建,什么时候不该建

student_course表上已经有唯一索引uk_student_course,它同时覆盖了student_id和course_id两个列,所以按student_id查选课记录时能直接走索引。但如果你经常按course_id查有哪些学生选了课,这个索引帮不上忙,因为唯一索引的最左前缀原则要求查询条件必须包含student_id。这时候就需要单独建一个索引:

CREATE INDEX idx_course_id ON student_course(course_id);

用EXPLAIN来验证一下:

EXPLAIN SELECT * FROM student_course WHERE course_id = 2;

type列的ref和key列的idx_course_id,说明走了索引。如果看到的type是ALL,表示全表扫描,数据量一大就会慢。第一次作业能会用EXPLAIN看执行计划已经超越绝大多数新人了。

但索引也不是越多越好。写过一篇博客讲过“索引是拿空间换时间”,每多一个索引,写入时就要多维护一棵B+树,所以只为高频查询列建索引,别把表里每个字段都套上。

7.2 数据量一大,为什么查询慢:从全表扫描到索引覆盖

给学生表多插10万条模拟数据,然后看一条查询:

SELECT COUNT(*) FROM student WHERE birth_date > '2001-01-01';

在没有任何索引的情况下,这个COUNT(*)需要扫全表。如果在birth_date上加索引:

CREATE INDEX idx_birth_date ON student(birth_date);

再看执行计划,会发现优化器选择走索引,扫描行数大幅下降。这就是为什么热词里会有“mysql性能调优”——很多情况下慢查询不是SQL写错了,而是没有合适的索引。

推动这一步的意义在于:第一次作业往往表里就几行数据,什么SQL都快,一旦上了生产,几百万行数据才见真章。所以作业阶段养成EXPLAIN的习惯,等遇到真正的慢查询时,你已经知道该从哪里入手。

7.3 锁与死锁:为什么你的UPDATE卡住了

另一个高深考点是锁。热搜词里出现过“mysql show full processlist killed”,这也确实是线上诊断必备技能。如果某个更新语句一直执行不完,很可能是有别的事务没提交,拿着行锁不放。这时候执行:

SHOW FULL PROCESSLIST;

能看到每个连接的当前状态。如果某个连接State是Waiting for table metadata lock或updating,可以确认它在等待锁。处理方式是:

-- 根据processlist查到的id杀掉阻塞源 KILL 12345;

KILL是最后手段,生产环境要谨慎使用,可能造成事务回滚。但对第一次作业来说,能用SHOW FULL PROCESSLIST观察SQL执行状态、理解锁的概念,已经是超出作业要求的程度了。

再提一个面试常问点:InnoDB的行锁不是“只锁一行”,而是基于索引加锁。如果你更新时WHERE条件没走索引,InnoDB会升级成锁全表记录,这就是网上常说的“不通过索引更新,行锁变表锁”。我在作业文档里让学生做过一次实验:先不加索引执行更新,开另一个会话更新不同ID的记录,结果被卡住;加索引后再试同样的操作,流畅通过。这个实验做一遍,对锁的理解会非常深刻。

8. 别只看MySQL本身:让作业体现“全栈视野”

一个让人印象深刻的作业,不会只有表和SQL,还应该体现你对整个技术栈的理解。我让学生至少做下面三件事之一:

第一,用JDBC写一个小Java程序,完成“输入学生姓名,查询他所有选的课和成绩”这个功能。涉及的关键点包括DriverManager、PreparedStatement、ResultSet、关闭连接。我在前面提过,JDBC的SSL连接报错以及serverTimezone配置,都会在这一步出现。直接把连接串写成:

String url = "jdbc:mysql://127.0.0.1:3306/school?useSSL=false&serverTimezone=Asia/Shanghai"; String user = "root"; String password = "123456"; try (Connection conn = DriverManager.getConnection(url, user, password); PreparedStatement ps = conn.prepareStatement( "SELECT c.course_name, sc.score FROM student s " + "JOIN student_course sc ON s.id = sc.student_id " + "JOIN course c ON c.id = sc.course_id " + "WHERE s.name = ?")) { ps.setString(1, "张三"); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { System.out.println(rs.getString("course_name") + " : " + rs.getBigDecimal("score")); } } }

用PreparedStatement而不是Statement,是因为它有预编译、防SQL注入,是生产规范。作业里能用上这个细节,面试官一眼就看得出受过正规训练。

第二,本地起一个Python脚本,用pymysql或mysql-connector-python读写MySQL,复现“录入学生信息并查询选课结果”的流程:

import pymysql conn = pymysql.connect( host="127.0.0.1", port=3306, user="root", password="123456", database="school", charset="utf8mb4" ) with conn.cursor() as cursor: cursor.execute( "INSERT INTO student (name, gender, birth_date) VALUES (%s, %s, %s)", ("赵六", "M", "2003-11-11") ) conn.commit() cursor.execute( "SELECT s.name, c.course_name, sc.score FROM student s " "JOIN student_course sc ON s.id = sc.student_id " "JOIN course c ON c.id = sc.course_id " "WHERE s.name = %s", ("赵六",) ) for row in cursor.fetchall(): print(row) conn.close()

Python脚本里同样用%s占位符,别拿字符串拼接SQL,习惯要从第一次作业就开始养。

第三,展示一次完整的备份与恢复操作,对应热搜词里“怎么使用mysql主从复制”、“把远程库的这张表同步到本地”这一类问题。第一步用mysqldump导出:

mysqldump -uroot -p school > school_backup.sql

第二步把备份文件传到另一台机器,恢复:

mysql -uroot -p school < school_backup.sql

结合作业要求,单独导出某张表:

mysqldump -uroot -p school student_course > student_course_only.sql

mysqldump单表导出时不会带建库语句,恢复前要先确保目标库存在。这个我上课时反复强调过,结果还是有人没建库直接导入导致报错。

把这三个方向加进作业,谈吐之间立刻从“我会建表”变成“我理解整个数据链路”。面试官喜欢这样的候选人,因为这意味着你能独立处理从存储到应用的完整闭环。

9. 复盘我的第一次作业:哪些坑最值得记

带过好几轮实习生,每个新人踩的坑都大同小异。我把最高频的五个问题集中列出来,你们写作业时可以直接对照检查:

问题典型报错原因解决
mysql命令找不到-bash: mysql: command not foundPATH中没包含MySQL二进制目录将/usr/local/mysql/bin加入PATH,或使用完整路径
socket文件缺失ERROR 2002 (HY000)服务未启动或 socket路径不一致检查服务状态;查看/etc/my.cnf的socket配置
密码验证失败ERROR 1045 (28000): Access denied密码错误或账号锁定重置密码;检查account_locked字段
表数据中文乱码???或 �客户端字符集与服务端不一致连接时加--default-character-set=utf8mb4,建库时用utf8mb4
数据重复Duplicate entry for key 'uk_student_course'唯一键冲突,或业务重复插入前先查重,或改用ON DUPLICATE KEY UPDATE

最后一个问题值得多讲两句。很多新人在作业中遇到唯一键冲突时,第一反应是“删掉唯一索引”,这就本末倒置了。唯一索引是约束数据重复的手段,冲突说明业务逻辑里可能没先查重就插入了。正确的做法有两种:一种是在应用层先SELECT判断再INSERT;另一种是直接用ON DUPLICATE KEY UPDATE,让数据库自己决定更新还是插入,效率更高。

我自己第一次用ON DUPLICATE KEY UPDATE时也有个疑问:它到底算INSERT还是UPDATE?实际上它在两种操作之间自适应,但对AUTO_INCREMENT列有个副作用——即使最终走了更新分支,自增值也会被消耗掉。所以如果你看到表的主键不是从1连续开始的,不要大惊小怪,这是自增机制的常见现象,不是数据错乱。

做完上面所有事情,这份作业就算圆满完成了。以我个人的经验,能把一个“最简单的选课库”做成这样,MySQL的日常开发能力已经足够应付绝大多数业务场景。后面再进阶的方向可以看存储引擎选择、备份恢复策略、读写分离方案、慢查询分析,但那些都是后话了。先把这次作业里的每一条SQL、每一个报错、每一次EXPLAIN的解读吃透,比囫囵吞枣刷一百道面试题都管用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 5:54:53

SAE J1939协议实战:PGN计算、29位ID拆解与多包传输解析

做商用车电控和诊断这几年&#xff0c;我发现很多人卡在SAE J1939上不是因为它难&#xff0c;而是没人把PGN计算、ID拆解、多包传输、报文解析这几件事串起来讲。你拿着CANalyzer或者周立功盒子抓一屏报文&#xff0c;满眼都是0x18FEF100、0x0CF00400、0x18ECFF00这种29位ID&am…

作者头像 李华
网站建设 2026/9/26 5:54:44

Java开发必知:MySQL函数高频用法与避坑指南

做 Java 开发这几年&#xff0c;我有个特别真切的感受&#xff1a;框架可以一个接一个地学&#xff0c;但 MySQL 函数这种东西&#xff0c;真的是用到哪查到哪&#xff0c;每次查完就忘&#xff0c;换个场景又得重新翻。这段时间我决定把 Java 这条老路重走一遍&#xff0c;第二…

作者头像 李华
网站建设 2026/9/26 5:54:07

MySQL自增主键与隐藏row_id:从原理到工程化排雷

前几天刚处理完一个线上的“怪故障”&#xff1a;某个订单表稳定运行了几年&#xff0c;某天开始持续报主键冲突&#xff0c;新数据写不进去。当时第一反应是某条脏数据导致的重复写入&#xff0c;查了很久才发现&#xff0c;这张表用的自增主键是int&#xff0c;而上限 214748…

作者头像 李华
网站建设 2026/9/26 5:53:54

U-Mamba复现第一步:conda环境、PyTorch与nnU-Net依赖配置详解

如果你最近在复现医学图像分割方向的论文&#xff0c;大概率绕不开 U-Mamba 这个名字。它是在 nnU-Net 基础上扩展出来的 3D 分割框架&#xff0c;算是“代码复现”圈子里热度很高的一份工作。作为一个跑过 U-Mamba 完整训练流程的人&#xff0c;我可以很负责任地说&#xff1a…

作者头像 李华
网站建设 2026/9/26 5:53:47

C语言printf格式符原理与实战:从内存到屏幕的全链路解析

1. 这不是语法表&#xff0c;是C语言输出的“翻译官说明书”你刚打开《C语言程序设计》教材第3章&#xff0c;看到printf("%d", age);这行代码&#xff0c;旁边标注着“%d表示整数”——但你心里其实有三个没说出口的问题&#xff1a;为什么非得用百分号开头&#xf…

作者头像 李华
网站建设 2026/9/26 5:52:45

从零到一:用 TaoToken 统一 Key 打通 AI 编程学习工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华