MySQL必备基础

MySQL必备基础

MySQL必备基础

仅仅阅读,是远没有实践记得清楚。
我将建表语句放在了这里:实验数据,可直接插入mysql
而本文的sql操作,统一采用的是这里的数据。
(如果点击无效,可以直接翻到文章末尾,具体代码在文末)

DML-插入

1、一句话总结:在什么场景下,解决了什么问题
新增业务数据(如注册用户、创建订单、写日志)场景下,insert 用来把新记录持久化到数据库,解决“数据从业务产生到落库保存”的问题。
2、2~4个关键词
insert into / values
3、2个基础,并直接能用的命令

-- 更新状态-- 1) 单行插入:新增一个用户(注意:显式写列名,最稳)insertinto`user`(id, username, nickname, email, city, created_at, updated_at)values(2002,'mike',null,'[email protected]','Beijing',now(),now());-- 2) 多行插入:一次插入多条日志(演示批量 values)insertinto`log`(id,level, message, created_at)values(60010,'info','new log 1',now()),(60011,'warn','new log 2',now());

4、1个坑,最容易翻车的点
不写列名导致列顺序一变就插错;最好永远写上列名。

DML-更新和删除

1、一句话总结:在什么场景下,解决了什么问题
改/删数据,用于修改业务状态。通过where进行精确定位,避免误伤。
2、2~4个关键词
delete / update / where/ limit
3、2个基础,并直接能用的命令

-- 更新状态update`orders`setstatus='PAID'where id =50002;-- 删除日志deletefrom`log`where created_at<NOW()-interval30day

4、1个坑,最容易翻车的点
delete中,漏写where,导致全表数据删除。

DQL-基础查询

1、一句话总结:在什么场景下,解决了什么问题
查数据并做列表,只拿需要的列,有条件,有分页。
2、2~4个关键词
select / distinct / 列投影 / as
3、2个基础,并直接能用的命令

select id,username fromuser;selectdistinct city fromuser;

4、1个坑,最容易翻车的点
select * 在查询大表/宽表时很慢,并且容易触发回表网络IO

DQL-条件查询

1、一句话总结:在什么场景下,解决了什么问题
where筛选,筛选出"我需要的数据"
2、2~4个关键词
where / like / or / between
3、2个基础,并直接能用的命令

-- 查今天已支付订单SELECT*FROM`orders`WHEREstatus='PAID'AND pay_time >= CURDATE();-- 查 username 以 a 开头 或 指定 id 集合SELECT*FROM`user`WHERE username LIKE'a%'OR id IN(1001,1002,1003);

4、1个坑,最容易翻车的点
null 不能用 " =null " ,而应该用 is null / is not null

DQL-聚合函数

1、一句话总结:在什么场景下,解决了什么问题
统计报表:总数,平均数,最大最小值
2、2~4个关键词
sum / avg / min / max
3、2个基础,并直接能用的命令

-- 总数selectcount(*)from orders wherestatus='PAID';-- 分组+平均数select dept_id,avg(salary)as avg_salary from emp groupby dept_id;

4、1个坑,最容易翻车的点
count(col) ,会忽略掉NULL值,所以用count(*),是最保底的选择。

DQL-分组查询

1、一句话总结:在什么场景下,解决了什么问题
分组聚合,并按 “维度查询
2、2~4个关键词
group by / having / 维度聚合
3、2个基础,并直接能用的命令

select city ,count(*)fromusergroupby city ;select city ,count(*)as c fromusergroupby city having c>2;

4、1个坑,最容易翻车的点
where vs having:其中,where过滤的是行,而having过滤的是聚合后的结果

DQL-排序查询

1、一句话总结:在什么场景下,解决了什么问题
列表,按照时间、分数…排序
2、2~4个关键词
order by / desc / asc
3、2个基础,并直接能用的命令

select*from`post`orderby created_at desc;select*from`post`orderby score desc, created_at desc;

4、1个坑,最容易翻车的点
大 OFFSET 排序很慢。(可以通过索引进行优化)

DQL-分页查询

1、一句话总结:在什么场景下,解决了什么问题
列表分页,解决 “只取一页的问题” 。
2、2~4个关键词
limit / offset / 深分页
3、2个基础,并直接能用的命令

select*from`post`orderby id desclimit5offset0;-- 游标分页(直接确定id,然后往前翻)select*from`post`where id<100000orderby id desclimit3;

4、1个坑,最容易翻车的点
深分页,如offset=10000会抛弃大量行,所以推荐使用游标分页。

DQL-案例联系

1、一句话总结:在什么场景下,解决了什么问题
综合使用
2、2~4个关键词
组合查询 / 可读性 / 逐步验证
3、2个基础,并直接能用的命令

-- 例:查北京用户的已支付订单列表SELECT o.id, o.amount, o.created_at, u.username FROM`orders` o JOIN`user` u ON o.user_id=u.id WHERE u.city='Beijing'AND o.status='PAID'ORDERBY o.created_at DESCLIMIT5;EXPLAINSELECT o.id, o.amount, o.created_at, u.username FROM`orders` o JOIN`user` u ON o.user_id=u.id WHERE u.city='Beijing'AND o.status='PAID'ORDERBY o.created_at DESCLIMIT5;

4、1个坑,最容易翻车的点
不 explain 就上生产,就很容易写出慢查询

DQL-执行顺序

1、一句话总结:在什么场景下,解决了什么问题
解释,为什么别名能够在having中用,而不能在where中用。
2、2~4个关键词
from / where / limit / select / group by / having
3、2个基础,并直接能用的命令

select dept_id,count(*)as c from emp groupby dept_id having c>1;

4、1个坑,最容易翻车的点
执行顺序
from > where > group by > having > select > order by > limit
原本按顺序,having应该也无法看到别名,但是mysql做了拓展。

DQL-小结

1、一句话总结:在什么场景下,解决了什么问题
查询 = “筛选(where)+聚合(group)+排序(order)+分页(limit)+索引(explain)”
2、2~4个关键词
explain 回表 索引
3、2个基础,并直接能用的命令

EXPLAINSELECT...;--暂时,还没怎么用过SHOWWARNINGS;(看优化器重写/警告) 

4、1个坑,最容易翻车的点
只会写代码,而不会检查,非常掉分。

DCL-用户管理

1、一句话总结:在什么场景下,解决了什么问题
管理账号与登录来源,用最小的权限,隔离环境
2、2~4个关键词
create user / alter user / drop user
3、2个基础,并直接能用的命令

createuser'user'@'localhost' identified by'123456';alteruser'user'@'localhost' identified by'1234';

4、1个坑,最容易翻车的点
‘user’@‘localhost’ 与 ‘user’@'%'是两条不同的账户,经常配错,出现能连/不能连的问题。(需注意优先级)

DCL-权限控制

1、一句话总结:在什么场景下,解决了什么问题
控制谁,能对某些表,进行特定的权限操作。避免越权误删
2、2~4个关键词
grant / revoke / show grants
3、2个基础,并直接能用的命令

grantselect,alteron interview_mysql.dept to'user'@'localhost';--展示权限show grants for'user'@'localhost'

4、1个坑,最容易翻车的点
直接给 grant all 是管理上的惰性,会给未来增加不可预测的风险。

DCL-小结

1、一句话总结:在什么场景下,解决了什么问题
账号=“主题”, 权限=“动作+资源范围”,原则=“最小权限”
2、2~4个关键词
最小权限 / 审计 / 账号隔离
3、2个基础,并直接能用的命令

-- 删除revokeselecton interview_mysql.dept from'user'@'localhost';-- 刷新,并清空 flush privileges;

4、1个坑,最容易翻车的点
误以为改了权限就会马上生效:alter/revoke在mysql中自动刷新,通常不需要flush。

函数-字符串函数

1、一句话总结:在什么场景下,解决了什么问题
清洗/格式化文本,拼接展示
2、2~4个关键词
concat / replace / substring / length
3、2个基础,并直接能用的命令

-- concat(..)组合-- coalesce(..)选取第一个非空select concat(username,'(',coalesce(nickname,'-'),')')as showName fromuser;--替换selectreplace(email,'@example.com','@demo.com')fromuser;

4、1个坑,最容易翻车的点
length()统计长度,中文可能会变长。用char_length()更合适。

函数-数据函数

1、一句话总结:在什么场景下,解决了什么问题
做 金额/评分/统计 时,需要用到的数值处理
2、2~4个关键词
round / ceil/floor / abs / decimal
3、2个基础,并直接能用的命令

select id,round(amount,2)as money from orders;select id,floor(amount),ceil(amount)as money from orders;

4、1个坑,最容易翻车的点
金额计算时别用浮点数存储,用decimal(10,2)-定点数,否则会有精度的坑。

函数-日期函数

1、一句话总结:在什么场景下,解决了什么问题
解决了数据分析时间报表中,对时间的分析与处理。
2、2~4个关键词
interval / date / date_add / timestampdiff
3、2个基础,并直接能用的命令

select*from orders where created_at>now()-interval7day;selectdate(created_at)as d ,count(*)as c from orders groupby d orderby c --计算时间差值(时间单位,time1,time2)select timestampdiff(day,date(created_at),'2025-11-20')as diff from orders 

4、1个坑,最容易翻车的点
应用/DB 时区不一致会导致时间错位。可以统一时区,或者用UTC。

函数-流程函数

1、一句话总结:在什么场景下,解决了什么问题
在sql层,做简单的分支控制 / 空值处理 / 分类统计
2、2~4个关键词
case / coalesce / if / when
3、2个基础,并直接能用的命令

SELECT id,COALESCE(nickname, username)AS show_name FROM`user`;selectsum(casewhenstatus='PAID'then1else0end)as paid_status,sum(casewhenstatus='CREATED'then1else0end)as created_status from orders;

4、1个坑,最容易翻车的点
case太复杂,会导致难以维护,应放在应用层。

约束-概述

1、一句话总结:在什么场景下,解决了什么问题
用约束保证数据的正确性:唯一/非空/范围…等等
2、2~4个关键词
primary key / unique / not null / check
3、2个基础,并直接能用的命令

showcreatetable`user`;showindexfrom`user`;

4、1个坑,最容易翻车的点
只靠代码约束不保底;并发下需要数据库进行保底。

约束-外键约束

1、一句话总结:在什么场景下,解决了什么问题
保证 “子表引用父亲合理化” ,避免孤儿数据。
2、2~4个关键词
foreign key / 父子表 / 引用完整性
3、2个基础,并直接能用的命令

showcreatetable`order_item`;-- 触发外键:order_id 不存在(会报 cannot add or update a child row)insertinto`order_item`(id, order_id, product_name, price, qty, created_at)values(79999,99999,'baditem',1.00,1,now());

4、1个坑,最容易翻车的点
外键可能会带来写入约束影响。因此在高并发场景下可能会替换 掉约束。

约束-小结

1、一句话总结:在什么场景下,解决了什么问题
约束=数据库的最后一道防线,尤其主键/唯一/非空这些是高频应用,而外键则需要另外考虑。
2、2~4个关键词
并发一致性 / 数据质量 / 兜底
3、2个基础,并直接能用的命令

showindexfrom`orders`;showcreatetable`orders`;

4、1个坑,最容易翻车的点
没有约束,仅靠业务查重,在并发场景下必翻车(典型:"先查后插"竞态)

多表关系介绍

1、一句话总结:在什么场景下,解决了什么问题
关系:一对一/一对多/多对多,决定表结构与连接方式。
2、2~4个关键词
1:1 / 1:n / n:m / 中间表
3、2个基础,并直接能用的命令

-- 多对多 连表查询select u.username, r.name as role_name from`user_role` ur join`user` u on ur.user_id = u.id join`role` r on ur.role_id = r.id where u.id =1001;-- 查看中间表showcreatetable`user_role`;

4、1个坑,最容易翻车的点
多对多表格中,需要建立中间表。如果硬塞逗号隔开 = 灾难(无法索引,无法约束,难以维护),

多表查询概述

1、一句话总结:在什么场景下,解决了什么问题
把多个表拼接成一个结果集
2、2~4个关键词
join连接表 / on筛选条件
3、2个基础,并直接能用的命令

select o.id, u.username, o.status, o.amount from`orders` o join`user` u on o.user_id=u.id;

4、1个坑,最容易翻车的点
如果忘写on或者条件写错,会导致笛卡尔积,结果爆炸且超慢。

内连接

1、一句话总结:在什么场景下,解决了什么问题
只要两边都匹配的记录:最常见的业务联表(inner join = join)
2、2~4个关键词
inner join / 等值连接
3、2个基础,并直接能用的命令

select o.id, u.username from`orders` o innerjoin`user` u on o.user_id = u.id;select o.id, u.username from`orders` o join`user` u on o.user_id = u.id;

4、1个坑,最容易翻车的点
列名冲突,一定要用o.id,否则会造成不同表格之间的列名冲突。

外连接

1、一句话总结:在什么场景下,解决了什么问题
保留一侧:“用户列表+是否下过订单”
2、2~4个关键词
left join / right join
3、2个基础,并直接能用的命令

-- 主表为:user,主表select u.id, u.username, o.id as order_id from`user` u leftjoin`orders` o on u.id = o.user_id;-- 只保留那些「没有任何订单匹配」的用户select u.*from`user` u leftjoin`orders` o on u.id = o.user_id where o.id isnull;

4、1个坑,最容易翻车的点
把右表on内的匹配条件,写到where中,会把left join 变成 inner join。
因为on决定是如何匹配,而where决定的是那些行能活下来

自连接

1、一句话总结:在什么场景下,解决了什么问题
一张表自己连自己:一般用于 组织关系/上下级/…
2、2~4个关键词
层级关系 / 别名
3、2个基础,并直接能用的命令

select e.name as emp_name, m.name as manager_name from`emp` e leftjoin`emp` m on e.manager_id = m.id;select*from`emp`where manager_id isnull;

4、1个坑,最容易翻车的点
别名起的不好,就会错列;自连接必须全程通过别名区分。

联合查询 union

1、一句话总结:在什么场景下,解决了什么问题
把两条查询上下拼接成一张结果(字段数与类型要对齐)
2、2~4个关键词
union 去重 / union all 不去重
3、2个基础,并直接能用的命令

-- 去重select id from`t_a`unionselect id from`t_b`;-- 不去重select id from`t_a`unionallselect id from`t_b`;

4、1个坑,最容易翻车的点
默认union会去重,稍慢。所以能用union all尽量就用这个。

子查询

1、一句话总结:在什么场景下,解决了什么问题
把一个查询的结果当成另一个查询的条件/表;常用于“先算出集合再过滤”
2、2~4个关键词
in / exists
3、2个基础,并直接能用的命令

-- r&d 部门的员工select*from`emp`where dept_id in(select id from`dept`where name ='r&d');-- exists 写法select*from`emp` e whereexists(select1from`dept` d where d.id = e.dept_id and d.name ='r&d');

4、1个坑,最容易翻车的点
子查询不一定慢,但相关子查询写不好会重复执行;能 JOIN 时也要会解释取舍。

标量子查询

1、一句话总结:在什么场景下,解决了什么问题
子查询返回单个值:用于“和某个统计值比较”。
2、2~4个关键词
scalar / 标量 / 聚合比较
3、2个基础,并直接能用的命令

SELECT*FROM`emp`WHERE salary >(SELECTAVG(salary)FROM`emp`);SELECT*FROM`orders`WHERE amount =(SELECTMAX(amount)FROM`orders`);

4、1个坑,最容易翻车的点
子查询返回多行会报错:Subquery returns more than 1 row,必须保证唯一加聚合 / limit

列子查询

1、一句话总结:在什么场景下,解决了什么问题
子查询返回一列多行:用于 IN/ANY/ALL。
2、2~4个关键词
in / any / all
3、2个基础,并直接能用的命令

select*from`emp`where dept_id in(select id from`dept`where city ='beijing');select*from`emp`where salary >all(select salary from`emp`where dept_id =10);

4、1个坑,最容易翻车的点
in 遇到 null 可能让逻辑变怪;必要时用 exists 更稳。
因为 sql 不是“二值逻辑”,而是“三值逻辑”:true / false / unknown(未知)。

可以动手看看,这个简单的例子:

--这样没啥问题select*from`emp`where id in(null,1,2); 真正会把你坑惨的,是 notin+nullselect*from`emp`where id notin(null,1,2); 明明有好几行符合条件的,却一行都不会返回!! 

行子查询

1、一句话总结:在什么场景下,解决了什么问题
自查询返回一行多列
2、2~4个关键词
row constructor / 多列比较
3、2个基础,并直接能用的命令

select*from`emp`where(dept_id, job)=(select dept_id, job from`emp`where id =2);

4、1个坑,最容易翻车的点
复合列要有合适联合索引,不然容易全表扫。

表子查询

1、一句话总结:在什么场景下,解决了什么问题
把子查询当作临时表 (派生表),在 join / 过滤
2、2~4个关键词
临时表 / derived table
3、2个基础,并直接能用的命令

select x.dept_id, x.c from(select dept_id,count(*)as c from emp groupby dept_id) x where x.c >2;select y.user_id, y.total_amount from(select user_id,sum(amount)as total_amount from orders groupby user_id) y orderby y.total_amount desclimit5;

4、1个坑,最容易翻车的点
派生表可能物化到临时表,数据量大很慢;尽量让派生表可被优化(字段少、条件早过滤)。

事务简介

1、一句话总结:在什么场景下,解决了什么问题
事务,用于把多步操作,变成"一同成功,或一同失败"
2、2~4个关键词
transaction / commit / rollback
3、2个基础,并直接能用的命令

starttransaction;commit;-- 或rollback;

4、1个坑,最容易翻车的点
MySQL 默认 autocommit=1,你以为在事务里其实不是;要么显式开启,要么在框架里确认。

事务演示

1、一句话总结:在什么场景下,解决了什么问题
必知步骤:开启事务 -> 更新 -> 异常回滚 -> 保证了一致性
2、2~4个关键词
锁 / 回滚 / 一致性
3、2个基础,并直接能用的命令

--开启事务starttransaction;update`account`set balance=balance-100, updated_at=now()where id=9001;update`account`set balance=balance+100, updated_at=now()where id=9002;--提交commit;

4、1个坑,最容易翻车的点
表引擎不是 InnoDB(如 MyISAM)不支持事务;面试一问就中招。

ACID四大特性

1、一句话总结:在什么场景下,解决了什么问题
用 ACID 解释“为什么事务可靠”:原子/一致/隔离/持久。
2、2~4个关键词
Atomic / Consistent / Isolated / Durable
3、2个基础,并直接能用的命令

-- 查看是否开启自动提交select @@autocommit;-- 查看隔离程度show variables like'transaction_isolation';

4、1个坑,最容易翻车的点
你说“有事务就绝对一致”不严谨:一致性还依赖约束、正确的业务逻辑与隔离级别。

并发事务问题

1、一句话总结:在什么场景下,解决了什么问题
并发下会出现:脏读、不可重复读、幻读。
2、2~4个关键词
dirty read / non-repeatable / phantom
3、2个基础,并直接能用的命令

setsessiontransactionisolationlevelreadcommitted;setsessiontransactionisolationlevelrepeatableread;

4、1个坑,最容易翻车的点
MySQL InnoDB 在 RR 隔离级别下,普通查询通过 MVCC 保证可重复读并避免幻读;而在范围更新或锁定读中,会通过行锁和间隙锁(Next-Key Lock)防止幻读,但这也可能导致范围锁定,从而引发意料之外的锁等待。

隔离级别

1、一句话总结:在什么场景下,解决了什么问题
不同的隔离级别,解决了什么问题?代价是什么?
2、2~4个关键词
RU / RC / RR / SERIALIZABLE / MVCC
3、2个基础,并直接能用的命令

starttransaction;select*from`account`where id=9001forupdate;-- 另一个会话可用共享锁读(mysql8 推荐 for share)select*from`account`where id=9001forshare;-- 提交/回滚释放锁commit;

4、1个坑,最容易翻车的点
for update 在无索引条件下可能锁全表/大量行;一定要让 where 走索引。

实验数据,可直接插入mysql

-- ========================================================= MySQL 8(InnoDB + utf8mb4) -- ========================================================= DROP DATABASE IF EXISTS interview_mysql; CREATE DATABASE interview_mysql DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; USE interview_mysql; -- 关闭安全更新(练习 UPDATE/DELETE 时更方便;生产不建议) SET SESSION sql_safe_updates = 0; -- ----------------------- -- 清理旧表(按外键依赖顺序) -- ----------------------- DROP TABLE IF EXISTS order_item; DROP TABLE IF EXISTS orders; DROP TABLE IF EXISTS post; DROP TABLE IF EXISTS user_role; DROP TABLE IF EXISTS role; DROP TABLE IF EXISTS account; DROP TABLE IF EXISTS emp; DROP TABLE IF EXISTS dept; DROP TABLE IF EXISTS log; DROP TABLE IF EXISTS t_a; DROP TABLE IF EXISTS t_b; DROP TABLE IF EXISTS user; -- ----------------------- -- 1) 用户表(DQL / NULL / 字符串函数) -- ----------------------- CREATE TABLE user ( id BIGINT PRIMARY KEY, username VARCHAR(32) NOT NULL UNIQUE, nickname VARCHAR(32) NULL, email VARCHAR(64) NOT NULL UNIQUE, city VARCHAR(32) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX idx_user_city (city), INDEX idx_user_created (created_at) ) ENGINE=InnoDB; -- ----------------------- -- 2) 角色表 + 多对多中间表(多表/约束) -- ----------------------- CREATE TABLE role ( id INT PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE ) ENGINE=InnoDB; CREATE TABLE user_role ( user_id BIGINT NOT NULL, role_id INT NOT NULL, PRIMARY KEY (user_id, role_id), CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES user(id), CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES role(id) ) ENGINE=InnoDB; -- ----------------------- -- 3) 部门/员工(JOIN + 自连接 + 聚合) -- ----------------------- CREATE TABLE dept ( id INT PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE, city VARCHAR(32) NOT NULL ) ENGINE=InnoDB; CREATE TABLE emp ( id INT PRIMARY KEY, name VARCHAR(32) NOT NULL, dept_id INT NOT NULL, manager_id INT NULL, job VARCHAR(32) NOT NULL, salary DECIMAL(10,2) NOT NULL, hired_at DATE NOT NULL, CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES dept(id), CONSTRAINT fk_emp_mgr FOREIGN KEY (manager_id) REFERENCES emp(id), INDEX idx_emp_dept (dept_id), INDEX idx_emp_mgr (manager_id), INDEX idx_emp_salary (salary) ) ENGINE=InnoDB; -- ----------------------- -- 4) 账户表(事务转账练习) -- ----------------------- CREATE TABLE account ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL UNIQUE, balance DECIMAL(12,2) NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT fk_acc_user FOREIGN KEY (user_id) REFERENCES user(id), INDEX idx_acc_balance (balance) ) ENGINE=InnoDB; -- ----------------------- -- 5) 订单/明细(JOIN / 外键 / 分组统计 / NULL pay_time) -- ----------------------- CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL, status VARCHAR(16) NOT NULL, -- CREATED/PAID/CANCELLED/REFUNDED amount DECIMAL(12,2) NOT NULL, created_at DATETIME NOT NULL, pay_time DATETIME NULL, updated_at DATETIME NOT NULL, CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES user(id), INDEX idx_orders_user (user_id), INDEX idx_orders_status_time (status, created_at), INDEX idx_orders_paytime (pay_time) ) ENGINE=InnoDB; CREATE TABLE order_item ( id BIGINT PRIMARY KEY, order_id BIGINT NOT NULL, product_name VARCHAR(64) NOT NULL, price DECIMAL(12,2) NOT NULL, qty INT NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT fk_item_order FOREIGN KEY (order_id) REFERENCES orders(id), INDEX idx_item_order (order_id) ) ENGINE=InnoDB; -- ----------------------- -- 6) 帖子表(排序/分页/统计) -- ----------------------- CREATE TABLE post ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL, title VARCHAR(128) NOT NULL, score INT NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT fk_post_user FOREIGN KEY (user_id) REFERENCES user(id), INDEX idx_post_score_time (score, created_at), INDEX idx_post_user (user_id) ) ENGINE=InnoDB; -- ----------------------- -- 7) 日志表(DML 删除练习:清理 30 天前) -- ----------------------- CREATE TABLE log ( id BIGINT PRIMARY KEY, level VARCHAR(8) NOT NULL, message VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, INDEX idx_log_time (created_at), INDEX idx_log_level (level) ) ENGINE=InnoDB; -- ----------------------- -- 8) UNION 练习用表 -- ----------------------- CREATE TABLE t_a ( id INT PRIMARY KEY ) ENGINE=InnoDB; CREATE TABLE t_b ( id INT PRIMARY KEY ) ENGINE=InnoDB; -- ========================================================= -- 插入数据 -- ========================================================= -- users(含 nickname NULL、不同城市、不同时间) INSERT INTO user (id, username, nickname, email, city, created_at, updated_at) VALUES (1001,'alice', '阿丽', '[email protected]', 'Beijing', '2025-11-01 10:00:00','2025-12-10 09:10:00'), (1002,'bob', NULL, '[email protected]', 'Beijing', '2025-11-05 11:00:00','2025-12-11 12:00:00'), (1003,'carol', '小C', '[email protected]', 'Shanghai', '2025-10-20 09:30:00','2025-12-09 08:00:00'), (1004,'dave', NULL, '[email protected]', 'Shanghai', '2025-11-12 16:20:00','2025-12-12 19:00:00'), (1005,'erin', 'E宝', '[email protected]', 'Shenzhen', '2025-11-18 14:00:00','2025-12-13 10:01:00'), (1006,'frank', NULL, '[email protected]', 'Shenzhen', '2025-11-21 17:45:00','2025-12-13 17:45:00'), (1007,'grace', '小G', '[email protected]', 'Guangzhou', '2025-10-01 08:00:00','2025-12-01 08:00:00'), (1008,'henry', NULL, '[email protected]', 'Guangzhou', '2025-09-15 09:00:00','2025-11-30 10:00:00'), (1009,'ivy', 'Ivy', '[email protected]', 'Hangzhou', '2025-11-30 20:00:00','2025-12-12 20:00:00'), (1010,'jack', NULL, '[email protected]', 'Hangzhou', '2025-12-01 09:00:00','2025-12-13 09:00:00'), (1011,'kate', 'K', '[email protected]', 'Beijing', '2025-10-10 10:10:10','2025-12-13 23:59:00'), (1012,'leo', NULL, '[email protected]', 'Shanghai', '2025-12-05 12:12:12','2025-12-12 12:12:12'); -- roles INSERT INTO role (id, name) VALUES (1,'admin'), (2,'merchant'), (3,'customer'); -- user_role(多对多) INSERT INTO user_role (user_id, role_id) VALUES (1001,1),(1001,3), (1002,3), (1003,2),(1003,3), (1004,3), (1005,2), (1006,3), (1007,3), (1008,3), (1009,3), (1010,3), (1011,1), (1012,3); -- dept INSERT INTO dept (id, name, city) VALUES (10,'R&D','Beijing'), (20,'Sales','Shanghai'), (30,'Ops','Shenzhen'); -- emp(自连接:先插 manager,再插下属) INSERT INTO emp (id, name, dept_id, manager_id, job, salary, hired_at) VALUES (1,'ZhangBoss', 10, NULL,'Director', 35000.00,'2022-01-01'), (2,'LiDev', 10, 1, 'Backend', 22000.00,'2023-03-15'), (3,'WangDev', 10, 1, 'Backend', 21000.00,'2023-06-01'), (4,'ChenQA', 10, 1, 'QA', 18000.00,'2024-02-20'), (5,'ZhaoSales', 20, NULL,'Manager', 26000.00,'2021-09-10'), (6,'SunSales', 20, 5, 'Sales', 16000.00,'2024-05-01'), (7,'WuOps', 30, NULL,'Manager', 24000.00,'2022-11-11'), (8,'HeSRE', 30, 7, 'SRE', 20000.00,'2024-08-08'); -- account(事务练习:转账) INSERT INTO account (id, user_id, balance, updated_at) VALUES (9001,1001,1000.00,'2025-12-13 10:00:00'), (9002,1002, 250.50,'2025-12-13 10:00:00'), (9003,1003, 88.80,'2025-12-13 10:00:00'), (9004,1004, 500.00,'2025-12-13 10:00:00'), (9005,1005, 999.99,'2025-12-13 10:00:00'), (9006,1006, 10.00,'2025-12-13 10:00:00'), (9007,1007, 66.66,'2025-12-13 10:00:00'), (9008,1008, 77.77,'2025-12-13 10:00:00'), (9009,1009, 300.00,'2025-12-13 10:00:00'), (9010,1010, 120.00,'2025-12-13 10:00:00'), (9011,1011,8888.88,'2025-12-13 10:00:00'), (9012,1012, 15.00,'2025-12-13 10:00:00'); -- orders(包含:已支付/未支付/取消/退款;也包含“无明细订单”用于 LEFT JOIN) INSERT INTO orders (id, user_id, status, amount, created_at, pay_time, updated_at) VALUES (50001,1001,'PAID', 128.00,'2025-12-01 10:00:00','2025-12-01 10:02:00','2025-12-01 10:02:00'), (50002,1001,'CREATED', 66.60,'2025-12-10 12:00:00',NULL, '2025-12-10 12:00:00'), (50003,1002,'PAID', 19.90,'2025-12-02 09:00:00','2025-12-02 09:01:00','2025-12-02 09:01:00'), (50004,1003,'CANCELLED', 58.00,'2025-11-20 18:30:00',NULL, '2025-11-20 18:45:00'), (50005,1003,'PAID', 199.00,'2025-12-05 20:00:00','2025-12-05 20:10:00','2025-12-05 20:10:00'), (50006,1004,'REFUNDED', 88.00,'2025-11-28 13:00:00','2025-11-28 13:05:00','2025-11-30 09:00:00'), (50007,1005,'PAID', 520.00,'2025-12-11 11:11:11','2025-12-11 11:12:00','2025-12-11 11:12:00'), (50008,1006,'CREATED', 39.90,'2025-12-12 15:00:00',NULL, '2025-12-12 15:00:00'), (50009,1009,'PAID', 15.00,'2025-12-03 08:00:00','2025-12-03 08:00:30','2025-12-03 08:00:30'), (50010,1010,'PAID', 88.88,'2025-12-13 09:09:09','2025-12-13 09:10:00','2025-12-13 09:10:00'); -- order_item(50002/50008 故意不给明细;练习“找无明细订单”) INSERT INTO order_item (id, order_id, product_name, price, qty, created_at) VALUES (70001,50001,'Keyboard', 128.00,1,'2025-12-01 10:00:10'), (70002,50003,'Notebook', 19.90,1,'2025-12-02 09:00:10'), (70003,50005,'Monitor', 199.00,1,'2025-12-05 20:00:10'), (70004,50006,'Mouse', 88.00,1,'2025-11-28 13:00:10'), (70005,50007,'Phone', 520.00,1,'2025-12-11 11:11:20'), (70006,50009,'Cable', 15.00,1,'2025-12-03 08:00:10'), (70007,50010,'Headset', 88.88,1,'2025-12-13 09:09:20'); -- posts(用于 ORDER BY / LIMIT / GROUP BY / HAVING) INSERT INTO post (id, user_id, title, score, created_at) VALUES (80001,1001,'MySQL 基础复盘', 98,'2025-12-01 09:00:00'), (80002,1001,'JOIN 面试题整理', 88,'2025-12-06 09:00:00'), (80003,1002,'分页优化:深分页到游标', 95,'2025-12-10 21:00:00'), (80004,1003,'事务与锁:RR 是否幻读', 93,'2025-12-08 20:00:00'), (80005,1003,'EXPLAIN 怎么看', 80,'2025-11-22 10:00:00'), (80006,1004,'子查询与 EXISTS 对比', 70,'2025-12-02 19:00:00'), (80007,1005,'外键要不要上生产', 85,'2025-12-03 13:00:00'), (80008,1006,'字符串函数清洗数据', 60,'2025-12-04 14:00:00'), (80009,1007,'GROUP BY + HAVING 实战', 92,'2025-12-05 16:00:00'), (80010,1008,'慢查询排查流程', 99,'2025-12-07 18:00:00'), (80011,1009,'NULL 处理:COALESCE', 75,'2025-12-09 08:00:00'), (80012,1010,'UNION vs UNION ALL', 65,'2025-12-12 08:30:00'); -- log(包含 30 天前的记录,练习 DELETE) INSERT INTO log (id, level, message, created_at) VALUES (60001,'INFO','service started', '2025-12-13 10:00:00'), (60002,'WARN','slow query detected', '2025-12-12 11:00:00'), (60003,'ERROR','db connection timeout', '2025-12-11 12:00:00'), (60004,'INFO','daily job finished', '2025-11-10 09:00:00'), (60005,'INFO','old log for cleanup (40d ago)', '2025-11-01 00:00:00'), (60006,'INFO','old log for cleanup (70d ago)', '2025-10-05 00:00:00'); -- UNION 练习数据 INSERT INTO t_a (id) VALUES (1),(2),(3),(10); INSERT INTO t_b (id) VALUES (3),(4),(5),(10); -- ========================================================= -- (可选)快速自检:确认数据量 -- ========================================================= -- SELECT COUNT(*) AS users FROM user; -- SELECT status, COUNT(*) FROM orders GROUP BY status; -- SELECT city, COUNT(*) FROM user GROUP BY city; 

本文为最小可复用笔记。


借鉴文章:
1、快速理解脏读、不可重复读、幻读和MVCC
2、六个案例搞懂间隙锁
3、什么是排他锁、共享锁、意向锁
4、chatgpt5.2
5、黑马MySQL


Read more

【C++】平衡树优化实战:如何手搓一棵查找更快的 AVL 树?

【C++】平衡树优化实战:如何手搓一棵查找更快的 AVL 树?

🎬 个人主页:MSTcheng · ZEEKLOG 🌱 代码仓库 :MSTcheng · Gitee 🔥 精选专栏: 《C语言》 《数据结构》 《C++由浅入深》 💬座右铭:路虽远行则将至,事虽难做则必成! 前言:前两篇文章我们已经向大家介绍了map和set这两个容器,他们的底层都是平衡二叉搜索树,而今天我们就来介绍一种平衡二叉搜索树——AVL树。 文章目录 * 一、AVL树的认识 * 1.1AVL树的概念 * 二、AVL树的实现 * 2.1AVL树的基本框架 * 2.2AVL树的插入 * 2.3AVL树的中序遍历 * 2.4AVL树其他功能实现 * 三、总结 一、AVL树的认识 1.1AVL树的概念 AVL树是由G. M. Adelson-Velsky和E. M. Landis两个前苏联的科学家所发明的,它的具体定义如下: * AVL树是最先发明的自平衡⼆叉查找树,AVL是⼀颗空树,

By Ne0inhk

【002】Windows系统下Java下载 JDK

文章目录 * @[TOC](文章目录) * 前言 * **1. 下载 JDK** * **2. 安装 JDK** * **3. 配置 JAVA_HOME 环境变量** * **4. 验证安装是否成功** * **常见问题与提示** 前言 这里下载安装的是 java17 的jdk 1. 下载 JDK * Oracle 官方 JDK 17: * 官网地址:https://www.oracle.com/java/technologies/downloads/#jdk17 * 注意:需要注册/登录 Oracle 账户。 * 或者选择 OpenJDK 17(推荐,无需登录): * 推荐发行版:Eclipse

By Ne0inhk
【LeetCode必刷好题】:Java顺序表实现杨辉三角

【LeetCode必刷好题】:Java顺序表实现杨辉三角

🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:Java.数据结构 【前言】 杨辉三角作为经典的数学与编程结合案例,是理解二维数组和动态列表操作的绝佳素材。本文将带你从逻辑拆解、问题分析、优化方向等角度进行详细解析,带你彻底掌握杨辉三角的实现精髓。 文章目录: * 一、杨辉三角思路分析 * 二、代码实现 * 三、总结 一、杨辉三角思路分析 杨辉三角每一行数字都是上一行两个相邻数字之和 思路分析: 创建一个二维列表List<List<Integer>>,储存整个三角外层循环控制行数 i,0~numRows内层循环是列数 j,小于 i每一行第一个和最后一个是1中间元素通过上一行相邻元素加得 二、代码实现 publicclassTest{publicList<List<Integer&

By Ne0inhk
计算机毕业设计java基于javaweb的超市销售管理系统 基于B/S架构的超市进销存与销售管理平台设计与实现 面向零售业的商品采购与销售订单管理系统开发

计算机毕业设计java基于javaweb的超市销售管理系统 基于B/S架构的超市进销存与销售管理平台设计与实现 面向零售业的商品采购与销售订单管理系统开发

计算机毕业设计java基于javaweb的超市销售管理系统2kf7s9 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。 随着零售行业的快速发展和市场竞争的日益激烈,超市作为商品流通的重要终端,其管理效率直接影响着经营成本和盈利能力。传统的超市销售管理多依赖于手工记账、纸质单据或单机Excel表格,存在商品信息更新不及时、库存管理混乱、销售数据难以统计、会员信息分散等问题,难以满足现代化超市对高效、精准、智能化管理的需求。基于JavaWeb的超市销售管理系统应运而生,它通过互联网技术将员工信息、会员档案、供应商管理、商品分类、商品信息、商品采购、销售订单等功能进行数字化整合,实现了超市销售全流程的线上化、规范化管理。该系统不仅提升了超市运营效率,也为管理者提供了数据驱动的决策支持,成为零售业数字化转型的重要工具。 系统核心功能概览: * 用户注册与登录:支持员工、管理员两类角色的注册与登录。 * 个人中心:用户可查看和修改个人资料,如员工工号、姓名、性别、手机、头像等。 * 员工管理:管理员可管理员工信

By Ne0inhk