0%

数据库操作

创建

名称若为关键词需用单引号

1
CREATE DATABASE [IF NOT_EXISTS] XX

查看/删除

1
2
3
SHOW DATABASES 查看数据库
SHOW CREATE DATABASE XXX 数据库创建语句
DROP DATABASE [IF EXITS] XX 删除数据库

备份恢复

必须在DOS执行
备份

1
mysqldump -u * -p * -B 数据库

生成 xx.sql文件
恢复

1
2
Source xx.sq了、

表操作

创建表

1
2
3
4
CREATE TABLE table_name
{
field datatype
}

character 字符集 (不指定默认用数据库字符集)
collate 校队规则
ENGINE

修改表

ALTER TABLE table_name

  • ADD 添加列
  • MODIFY 修改列
  • DROP 删除列
  • Rename table name to new_name 修改表名
  • ALTER table name character set 字符集 修改字符集
  • NOT NULL DEFAULT 默认不为空
  • DESC 查看字段

数据类型

数值类型

  1. 整型

     tinyint[1字节] (-127~127) unsigned(0~255)
     smallint[2]
     mediumint[3]
     int[4]
     bigint[8]
    
  2. 小数类型

     float[4]
     double[8]
     decimal[M,D] (M为小数位数总数,D为小数点后的位数)(M默认10,D默认0)max(65,30)
    

文本类型

  1. char(0~255)
  2. varchar(065535[2^16-1]) 注:utf-8编码最大21844(65535 - 3)/3 13个字节用于记录大小
  3. text(0~2^16-1)
  4. longtext(2^32-1)

细节

  • 1.char(4)和varchar(4)中的4表示字符
  • 2.char(4)是定长,varchar(4)是变长

二进制数据

  1. blob(0~2^16-1)
  2. longblob(2^32-1)

日期

  1. date [日期 年月日]
  2. time [时间 时分秒]
  3. datetime [YYYY-MM-DD HH:mm:ss]
  4. timestamp 时间戳 自动更新:NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

增删改查

INSERT

1
2
INSERT INTO table_name(columns)
VALUES (具体数值)

注意:

  1. 日期和字符数据需包含在单引号中
  2. 可以插入空值
  3. insert into table () values (),(),()可以添加多条记录
  4. 给表中所有字段添加数据可以不写字段名称

UPDATE

1
2
3
UPDATE name
SET COLUNMS
(WHERE ...)

DETELE

1
2
DELETE name FROM
WHERE ...

注意:

  1. delete不能单独删除一列的数据
  2. delete只删除记录。不删除表本身

SELECT

1
2
SELECT [DISTINCT] * | {COLUMN}
FROM table_name

注意:

  1. DISTINCT 是否去重
  2. 使用表达式对查询的列进行运算:
1
2
SELECT *|{COLUMN1|EXPRESSION}
FROM table_name
  1. AS 语句
1
SELECT column_name as 别名 from table
  1. WHERE 子句:条件筛选

🔹 逻辑运算符(组合条件)

运算符 说明
AND 逻辑与(全部为真才真)
OR 逻辑或(任一为真即真)
NOT 逻辑非(取反)

✅ 注意:AND 优先级高于 OR,建议用括号 () 明确逻辑分组,例如:

1
WHERE (status = 'active' OR level > 5) AND NOT is_deleted

🔹 比较运算符(判断单值/集合)

类型 运算符 / 语法 示例
常规比较 =, <>!=, <, <=, >, >= age > 18
区间匹配 BETWEEN val1 AND val2 score BETWEEN 60 AND 100(含边界)
集合成员判断 IN (val1, val2, ...) dept_id IN (1, 3, 5)
模糊匹配 LIKE / NOT LIKE + 通配符 name LIKE 'A%'%:任意字符,_:单字符)
空值判断(⚠️特殊) IS NULL / IS NOT NULL email IS NULL(不能用 = NULL!)

📌 提示:

  • NULL 表示“缺失/未知”,任何与 NULL 的比较(如 =, !=)结果均为 UNKNOWN
  • 字符串模糊匹配注意大小写敏感性(依赖数据库设置,如 MySQL 默认不区分,PostgreSQL 区分)。
  1. ORDER BY 排序查询结果
  • 升序 ASC
  • 降序 DESC

合计函数 COUNT

返回行的总数
SELECT COUNT *|COLUMN FROM table_name

合计函数 SUM

返回满足WHERE条件的行的和

1
SELECT SUM (COLUMN) FROM table_name

合计函数 AVG

返回平均值

1
SELECT AVG (COLUMN) FROM table_name

合计函数 MAX/MIN

1
SELECT MAX/MIN (COLUMN) FROM table_name

GROUP BY 分组查询 + HAVING 限制显示结果

字符串函数

🔤 一、基础操作

函数 说明 示例
LENGTH(str) 返回字符串的字节长度(注意:UTF8 中中文占 3 字节) LENGTH('你好')6
CHAR_LENGTH(str)CHARACTER_LENGTH(str) 返回字符串的字符个数 CHAR_LENGTH('你好')2
UPPER(str) / UCASE(str) 转大写 UPPER('Hello')'HELLO'
LOWER(str) / LCASE(str) 转小写 LOWER('Hello')'hello'
TRIM([{BOTH|LEADING|TRAILING} [remstr] FROM] str) 去除首尾空格或指定字符 TRIM(' abc ')'abc'
TRIM(BOTH 'x' FROM 'xxabcxx')'abc'
LTRIM(str) 去除左侧空格 LTRIM(' abc')'abc'
RTRIM(str) 去除右侧空格 RTRIM('abc ')'abc'

🔗 二、拼接与拆分

函数 说明 示例
CONCAT(str1, str2, …) 拼接字符串(任一参数为 NULL,结果为 NULL CONCAT('a', 'b', 'c')'abc'
CONCAT_WS(sep, str1, str2, …) 用分隔符拼接(自动跳过 NULL CONCAT_WS(',', 'a', NULL, 'c')'a,c'
SUBSTRING(str, pos[, len])
SUBSTR(str, pos[, len])
从第 pos 位(从 1 开始)截取 len 个字符;pos 可为负(从末尾算) SUBSTR('MySQL', 2, 3)'ySQ'
SUBSTR('MySQL', -3)'SQL'
LEFT(str, n) 取左边 n 个字符 LEFT('MySQL', 3)'MyS'
RIGHT(str, n) 取右边 n 个字符 RIGHT('MySQL', 2)'QL'

🔍 三、查找与定位

函数 说明 示例
LOCATE(substr, str[, pos]) 返回 substrstr 中首次出现的位置(从 1 开始),可指定起始位置 LOCATE('S', 'MySQL')3
LOCATE('Q', 'MySQL', 4)4
INSTR(str, substr) LOCATE(substr, str),但参数顺序相反(兼容 Oracle) INSTR('MySQL', 'S')3
POSITION(substr IN str) LOCATE,标准 SQL 写法 POSITION('S' IN 'MySQL')3

🛠️ 四、替换与格式化

函数 说明 示例
REPLACE(str, from_str, to_str) str 中所有 from_str 替换为 to_str REPLACE('a-b-c', '-', '/')'a/b/c'
INSERT(str, pos, len, newstr) strpos 处删除 len 个字符,插入 newstr INSERT('Quadratic', 3, 4, 'What')'QuWhattic'
LPAD(str, len, pad) 左填充:用 padstr 补至 len 长(超长则截断) LPAD('abc', 5, '0')'00abc'
RPAD(str, len, pad) 右填充 RPAD('abc', 5, 'x')'abcxx'
REPEAT(str, n) str 重复 n REPEAT('Ha', 3)'HaHaHa'

五、高级处理(MySQL 8.0+)

函数 说明 示例
REGEXP_LIKE(str, pattern[, match_type]) 正则匹配(返回 1/0) SELECT 'abc123' REGEXP '^[a-z]+[0-9]+$'1
REGEXP_SUBSTR(str, pattern[, pos[, occ[, match_type]]]) 提取匹配的子串 REGEXP_SUBSTR('user@example.com', '@(.+)', 1, 1, 'i', 1)'example.com'
REGEXP_REPLACE(str, pattern, replace_str[, pos[, occ[, match_type]]]) 正则替换 REGEXP_REPLACE('abc123def', '[0-9]+', '#')'abc#def'
REGEXP_INSTR(str, pattern[, pos[, occ[, return_opt[, match_type]]]]) 返回匹配位置(支持更灵活控制) REGEXP_INSTR('abc123def', '[0-9]+')4

数学函数

以下是 MySQL 中常用的数学类函数(Mathematical Functions),适用于 MySQL 5.7 / 8.0+,按功能分类整理,附典型用法与注意事项。


一、基本运算与取整

函数 说明 示例 注意
ABS(X) 绝对值 ABS(-5)5 支持整数、浮点、DECIMAL
SIGN(X) 符号函数:正→1,负→-1,零→0 SIGN(-3.2)-1
MOD(N, M)N % MN MOD M 取模(余数) MOD(10, 3)1
-10 MOD 3-1
负数取模结果符号与被除数一致
FLOOR(X) 向下取整(不大于 X 的最大整数) FLOOR(3.9)3
FLOOR(-3.2)-4
CEIL(X) / CEILING(X) 向上取整(不小于 X 的最小整数) CEIL(3.1)4
CEIL(-3.2)-3
ROUND(X[, D]) 四舍五入;D 为小数位数(默认 0) ROUND(3.456, 2)3.46
ROUND(123, -1)120
D 可为负(对整数位取整)
TRUNCATE(X, D) 截断(直接舍弃小数,不四舍五入 TRUNCATE(3.999, 1)3.9
TRUNCATE(123.456, -1)120
常用于精度控制

二、幂、指数与对数

函数 说明 示例
POW(X, Y) / POWER(X, Y) X 的 Y 次方 POW(2, 3)8
POW(4, 0.5)2(开平方)
SQRT(X) 平方根(X ≥ 0) SQRT(16)4
EXP(X) e 的 X 次方 EXP(1)2.718281828459045
LN(X) 自然对数(以 e 为底,X > 0) LN(EXP(2))2
LOG(X) 自然对数(同 LN(X) LOG(2.71828)1
LOG(B, X) 以 B 为底的对数(X > 0, B > 0, B ≠ 1) LOG(10, 1000)3
LOG2(X) 以 2 为底的对数 LOG2(8)3
LOG10(X) 以 10 为底的对数 LOG10(100)2

三、三角函数(角度单位:弧度

函数 说明 示例
SIN(X), COS(X), TAN(X) 正弦、余弦、正切 SIN(PI()/2)1
ASIN(X), ACOS(X), ATAN(X) 反正弦、反余弦、反正切 ASIN(1)1.570796...(≈π/2)
ATAN(Y, X)ATAN2(Y, X) 四象限反正切(返回点 (X, Y) 的角度) ATAN2(1, 1)0.785398...(≈π/4)
COT(X) 余切(= 1 / TAN(X)) COT(PI()/4)1
DEGREES(X) 弧度 → 角度 DEGREES(PI())180
RADIANS(X) 角度 → 弧度 RADIANS(180)3.141592653589793

⚠️ 注意:三角函数入参为弧度,若需角度计算,先用 RADIANS() 转换。


四、随机数

函数 说明 示例
RAND() 返回 [0, 1) 之间随机浮点数 RAND()0.732...
RAND(N) 用种子 N 初始化,之后每次调用 RAND() 生成可重现序列 SELECT RAND(1), RAND(), RAND(); → 每次执行结果一致

✅ 生成 [a, b] 区间随机整数:

1
2
3
FLOOR(a + RAND() * (b - a + 1))
-- 例如生成 [1, 100]:
SELECT FLOOR(1 + RAND() * 100);

五、进制与位运算(部分)

函数 说明 示例
BIN(N) 十进制 → 二进制字符串 BIN(10)'1010'
OCT(N) 十进制 → 八进制字符串 OCT(10)'12'
HEX(N) / HEX(str) 十进制 → 十六进制字符串;或字符串转 HEX HEX(255)'FF'
HEX('A')'41'
CONV(N, from_base, to_base) 任意进制转换(2~36 进制) CONV('FF', 16, 10)'255'
CONV('1010', 2, 16)'A'

实用示例

  1. 计算用户年龄(假设 birth_date 为 DATE 类型)

    1
    2
    3
    4
    SELECT 
    name,
    FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25) AS age
    FROM users;
  2. 评分归一化到 [0, 100]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT 
    score,
    ROUND(100 * (score - min_score) / (max_score - min_score), 1) AS normalized_score
    FROM (
    SELECT score,
    (SELECT MIN(score) FROM exams) AS min_score,
    (SELECT MAX(score) FROM exams) AS max_score
    FROM exams
    ) t;
  3. 生成带随机延迟的模拟数据

    1
    2
    SELECT 
    NOW() + INTERVAL FLOOR(RAND() * 3600) SECOND AS random_time;

以下是 MySQL 中常用的日期与时间函数(Date and Time Functions),适用于 MySQL 5.7 / 8.0+,按功能分类整理,附详细说明、典型示例与实用技巧。


一、获取当前日期/时间

函数 说明 示例 返回类型
NOW() / SYSDATE() 当前日期时间(YYYY-MM-DD HH:MM:SS NOW()'2025-12-07 15:30:45' DATETIME
CURDATE() / CURRENT_DATE 当前日期 CURDATE()'2025-12-07' DATE
CURTIME() / CURRENT_TIME 当前时间 CURTIME()'15:30:45' TIME
UTC_DATE() UTC 日期 UTC_DATE()'2025-12-07' DATE
UTC_TIME() UTC 时间 UTC_TIME()'07:30:45' TIME
UTC_TIMESTAMP() UTC 日期时间 UTC_TIMESTAMP()'2025-12-07 07:30:45' DATETIME

NOW() 返回语句开始执行时的时间;SYSDATE() 返回函数执行时的时间(在 SLEEP() 或触发器中差异明显)。


二、日期时间构造与提取

函数 说明 示例
DATE(expr) 提取日期部分 DATE('2025-12-07 15:30:45')'2025-12-07'
TIME(expr) 提取时间部分 TIME('2025-12-07 15:30:45')'15:30:45'
YEAR(date) 年份(1000–9999) YEAR('2025-12-07')2025
MONTH(date) 月份(1–12) MONTH('2025-12-07')12
DAY(date) / DAYOFMONTH(date) 日期(1–31) DAY('2025-12-07')7
HOUR(time) 小时(0–23) HOUR('15:30:45')15
MINUTE(time) 分钟(0–59) MINUTE('15:30:45')30
SECOND(time) 秒(0–59) SECOND('15:30:45')45
DAYOFWEEK(date) 星期几(1=周日, 2=周一,…,7=周六) DAYOFWEEK('2025-12-07')1(2025-12-07 是周日)
WEEKDAY(date) 星期几(0=周一, 1=周二,…,6=周日) WEEKDAY('2025-12-07')6
DAYOFYEAR(date) 一年中的第几天(1–366) DAYOFYEAR('2025-12-07')341
WEEK(date[, mode]) 一年中的第几周(mode 控制起始日与范围) WEEK('2025-12-07')49(默认周日为每周首日)
YEARWEEK(date[, mode]) 返回 YYYYWW 格式(年+周) YEARWEEK('2025-12-07')202549

推荐用 WEEK(date, 1)周一为每周首日,第1周需 >=4 天(ISO 标准兼容)。


三、日期时间格式化与解析

函数 说明 示例
DATE_FORMAT(date, format) 按格式输出日期字符串 DATE_FORMAT(NOW(), '%Y年%m月%d日 %H:%i')'2025年12月07日 15:30'
TIME_FORMAT(time, format) 按格式输出时间字符串 TIME_FORMAT('15:30:45', '%H时%i分')'15时30分'
STR_TO_DATE(str, format) 按格式将字符串转为日期/时间 STR_TO_DATE('2025/12/07', '%Y/%m/%d')'2025-12-07'

常用格式符(DATE_FORMAT / STR_TO_DATE

格式符 说明 示例
%Y 4 位年 2025
%y 2 位年 25
%m 2 位月(01–12) 12
%c 月(1–12,无前导零) 12
%d 2 位日(01–31) 07
%e 日(1–31,无前导零) 7
%H 24 小时制(00–23) 15
%h / %I 12 小时制(01–12) 03
%i 分钟(00–59) 30
%s / %S 秒(00–59) 45
%p AM/PM PM
%W 星期名(英文全称) Sunday
%a 星期缩写 Sun
%M 月名(英文全称) December
%b 月缩写 Dec

示例:中文日期格式

1
2
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %W %H:%i');
-- 输出:2025年12月07日 Sunday 15:30

四、日期时间运算(加减间隔)

核心函数:DATE_ADD() / DATE_SUB() / INTERVAL

函数 说明 示例
DATE_ADD(date, INTERVAL expr unit) 日期加间隔 DATE_ADD('2025-12-07', INTERVAL 3 DAY)'2025-12-10'
DATE_SUB(date, INTERVAL expr unit) 日期减间隔 DATE_SUB(NOW(), INTERVAL 1 HOUR) → 1 小时前
date + INTERVAL expr unit 等价于 DATE_ADD(更简洁) CURDATE() + INTERVAL 7 DAY → 7 天后
date - INTERVAL expr unit 等价于 DATE_SUB NOW() - INTERVAL 30 MINUTE → 30 分钟前

支持的 unit 类型(常用)

单位 说明 示例
DAY, HOUR, MINUTE, SECOND 日、时、分、秒 INTERVAL 2 HOUR
WEEK, MONTH, QUARTER, YEAR 周、月、季、年 INTERVAL 1 MONTH
DAY_HOUR '天 小时' 格式 INTERVAL '2 05' DAY_HOUR → 2天5小时
HOUR_MINUTE '小时:分' 格式 INTERVAL '1:30' HOUR_MINUTE → 1小时30分
MINUTE_SECOND '分:秒' 格式 INTERVAL '30:15' MINUTE_SECOND → 30分15秒
YEAR_MONTH '年-月' 格式 INTERVAL '1-6' YEAR_MONTH → 1年6个月

示例:获取本月第一天/最后一天

1
2
3
4
5
6
7
8
9
-- 本月第一天
SELECT DATE_FORMAT(CURDATE(), '%Y-%m-01');
-- 或
SELECT CURDATE() - INTERVAL DAYOFMONTH(CURDATE())-1 DAY;

-- 本月最后一天(MySQL 8.0+ 推荐)
SELECT LAST_DAY(CURDATE());
-- 兼容旧版:
SELECT DATE_ADD(DATE_FORMAT(CURDATE(), '%Y-%m-01'), INTERVAL 1 MONTH) - INTERVAL 1 DAY;

五、日期差值计算

函数 说明 示例
DATEDIFF(expr1, expr2) 日期差(天数),忽略时间部分 DATEDIFF('2025-12-10', '2025-12-07')3
TIMEDIFF(expr1, expr2) 时间差(TIME 类型),仅限 TIME 或同日 DATETIME TIMEDIFF('15:30:00', '14:00:00')'01:30:00'
TIMESTAMPDIFF(unit, datetime1, datetime2) 按指定单位计算差值(更灵活) TIMESTAMPDIFF(HOUR, '2025-12-07 10:00', NOW()) → 相差小时数

TIMESTAMPDIFFunitYEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND
示例:计算年龄(精确到月)

1
2
3
4
5
SELECT 
name,
TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age_years,
TIMESTAMPDIFF(MONTH, birth_date, CURDATE()) % 12 AS extra_months
FROM users;

六、其他实用函数

函数 说明 示例
LAST_DAY(date) 返回该月最后一天 LAST_DAY('2025-02-10')'2025-02-28'
MAKEDATE(year, dayofyear) 用年份 + 年内第几天构造日期 MAKEDATE(2025, 341)'2025-12-07'
MAKETIME(hour, minute, second) 构造时间 MAKETIME(15, 30, 45)'15:30:45'
FROM_DAYS(N) 将天数(自公元0年1月1日起)转为日期 FROM_DAYS(738864)'2025-12-07'
TO_DAYS(date) 日期转天数(同上) TO_DAYS('2025-12-07')738864

数学类函数


一、基础算术与取整

函数 说明 示例 返回类型
ABS(X) 绝对值 ABS(-5.3)5.3 与输入一致(DECIMAL/DOUBLE/BIGINT
SIGN(X) 符号:正→1,负→-1,零→0 SIGN(-10)-1 整数
MOD(N, M)
N % M
N MOD M
取模(余数) MOD(17, 5)2
MOD(-17, 5)-2
N
FLOOR(X) 向下取整(≤ X 的最大整数) FLOOR(3.9)3
FLOOR(-2.1)-3
整数
CEIL(X) / CEILING(X) 向上取整(≥ X 的最小整数) CEIL(3.1)4
CEIL(-2.1)-2
整数
ROUND(X)
ROUND(X, D)
四舍五入;D 为小数位(默认 0)
注意:当小数位为 5 时,向最近偶数取整(银行家舍入)
ROUND(2.5)2
ROUND(3.5)4
ROUND(123.456, 2)123.46
ROUND(123.456, -1)120
同输入(D=0 时为整数)
TRUNCATE(X, D) 截断(直接舍弃,不四舍五入 TRUNCATE(3.999, 2)3.99
TRUNCATE(123, -1)120
同输入

ROUND 的“银行家舍入”说明:
ROUND(1.5) = 2ROUND(2.5) = 2ROUND(3.5) = 4 —— 避免统计偏差。


二、幂、指数与对数

函数 说明 示例
POW(X, Y) / POWER(X, Y) X 的 Y 次方 POW(2, 3)8
POW(25, 0.5)5(开方)
SQRT(X) 平方根(X ≥ 0) SQRT(16)4
EXP(X) eX(自然指数) EXP(1)2.718281828459045
LN(X) 自然对数(logeX,X > 0) LN(EXP(2))2
LOG(X) LN(X) LOG(2.71828)1
LOG(B, X) 以 B 为底的对数(B > 0, B ≠ 1, X > 0) LOG(2, 8)3
LOG2(X) 以 2 为底对数(常用于信息熵、位运算) LOG2(1024)10
LOG10(X) 以 10 为底对数(常用对数) LOG10(1000)3

输入为负或零时,对数函数返回 NULL 并警告。


三、三角函数(弧度制

函数 说明 示例
PI() 返回 π(≈ 3.141593) PI()3.141593
SIN(X) 正弦(X 为弧度) SIN(PI()/2)1
COS(X) 余弦 COS(0)1
TAN(X) 正切 TAN(PI()/4)1
ASIN(X) 反正弦(值域 [-1,1]) ASIN(1)1.570796(≈π/2)
ACOS(X) 反余弦(值域 [-1,1]) ACOS(0)1.570796
ATAN(X) 反正切(单参数) ATAN(1)0.785398(≈π/4)
ATAN(Y, X) / ATAN2(Y, X) 四象限反正切(推荐用 ATAN2 ATAN2(1, 1)0.785398
ATAN2(-1, -1)-2.356194(第三象限)
COT(X) 余切 = 1 / TAN(X) COT(PI()/4)1
DEGREES(X) 弧度 → 角度 DEGREES(PI())180
RADIANS(X) 角度 → 弧度 RADIANS(90)1.570796

角度计算模板:

1
2
-- 计算 30 度的正弦值
SELECT SIN(RADIANS(30)); -- → 0.5

四、随机数

函数 说明 示例
RAND() 返回 [0, 1) 的随机浮点数 SELECT RAND();0.7321...
RAND(N) 用种子 N 初始化随机数生成器,之后调用 RAND() 可重现序列 SELECT RAND(1), RAND(), RAND();
→ 每次执行结果相同

常用随机数生成公式

1
2
3
4
5
6
7
8
-- [a, b] 区间随机整数(含端点)
SELECT FLOOR(a + RAND() * (b - a + 1));

-- 示例:生成 [1, 100] 随机整数
SELECT FLOOR(1 + RAND() * 100);

-- 生成 6 位随机数字验证码
SELECT LPAD(FLOOR(RAND() * 1000000), 6, '0');

五、进制与位运算辅助(部分)

函数 说明 示例
BIN(N) 十进制 → 二进制字符串 BIN(10)'1010'
OCT(N) 十进制 → 八进制字符串 OCT(9)'11'
HEX(N) 十进制 → 十六进制字符串 HEX(255)'FF'
CONV(N, from_base, to_base) 任意进制转换(2~36 进制) CONV('FF', 16, 10)'255'
CONV('1010', 2, 16)'A'

注意:BIN(), HEX() 等返回的是字符串,不是数值。


六、聚合中的数学应用(补充)

虽属聚合函数,但常与数学结合:

1
2
3
4
5
6
7
8
SELECT
AVG(score) AS avg_score,
STDDEV_POP(score) AS population_std, -- 总体标准差
STDDEV_SAMP(score) AS sample_std, -- 样本标准差(更常用)
VARIANCE(score) AS variance,
-- 百分位(MySQL 8.0+)
PERCENT_RANK() OVER (ORDER BY score) AS pct_rank
FROM scores;

STDDEV_POP vs STDDEV_SAMP

  • 总体标准差:分母为 N
  • 样本标准差:分母为 N-1(无偏估计)

附:常见错误与注意事项

问题 说明
ROUND(2.5) ≠ 3 因采用银行家舍入(向最近偶数取整)
MOD(-7, 3) = -1 MySQL 中 MOD(a,b) 符号与 a 一致(不同于 Python)
三角函数输入为角度 必须先用 RADIANS() 转换
LOG(0) / LOG(-1) 返回 NULL(对数定义域限制)
SQRT(-1) 返回 NULL(实数域无解)

加密函数

  1. USER() 查询用户
  2. DATABASE() 当前数据库名称
  3. MD5(str)
  4. PASSWORD(str)
  5. SELECT * FROM mysql.user \G

流程控制函数

  1. IF
  2. IFNULL
  3. SELECT CASE XX THEN XX

查询增强

  • LIKE % 表示0到多个字符 、 - 表示单个字符

分页查询

1
SELECT XXX LIMIT START, LOWS

从start + 1 开始,取rows行

公式:

1
LIMIT 每页显示数 * 第几页 - 1,每页显示数

多表查询

直接查询两张表

从第一张表N取一行与第二张表M每一行进行组合,一共返回 N * M 行

解决方法

WHERE 过滤

注:查询条件不能少于 表数 - 1,否则会出现笛卡尔积

若表 A 有 1万 行,表 B 有 1万 行,笛卡尔积就是 1亿行

自连接

  1. 把一张表当两张表用
  2. 需要给表起别名

子查询

单行子查询

子查询返回 0 行或 1 行(即至多一行结果)。

1
2
3
4
-- 查询工资高于平均工资的员工
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees); -- ← 单行子查询(AVG 返回一个值)

多行子查询

  • 必须配合多行操作符使用

常用操作符:

  • IN:等于列表中任意一个值
  • NOT IN:不等于列表中所有值
  • ANY / SOME:与子查询结果中的任意一个比较为真即满足
  • ALL:与子查询结果中的所有值比较都为真才满足
1
2
3
4
5
6
7
-- 查询工资高于“任一”经理工资的员工
SELECT name, salary
FROM employees
WHERE salary > ANY (
SELECT salary FROM employees WHERE job_title = '经理'
);
-- 等价于:salary > (子查询中最小的经理工资)

多列子查询

返回多个列数据的子查询语句。

1
2
3
4
5
6
7
8
-- 高薪岗位定义:salary > 10000 的 (dept_id, job_title) 组合
SELECT name, dept_id, job_title
FROM employees
WHERE (dept_id, job_title) IN (
SELECT dept_id, job_title
FROM employees
WHERE salary > 10000
);

数据库会把 (col1, col2) 视为一个逻辑元组(tuple) 进行匹配。

表复制

只复制表结构

1
CREATE TABLE new_table LIKE old_table;

复制全部数据

1
2
CREATE TABLE new_table AS
SELECT * FROM old_table;

合并查询

合并查询”在 SQL 中通常指将多个查询结果集纵向拼接为一个结果集,核心语法是 UNIONUNION ALLINTERSECTEXCEPT(或 MINUS)。下面以标准 SQL 为主,结合主流数据库(MySQL / PostgreSQL / Oracle / SQL Server)差异,系统讲解:


✅ 一、核心操作符对比

操作符 作用 去重? 排序? MySQL PostgreSQL SQL Server Oracle
UNION 合并结果,去重 ✅(隐式按列排序) ✔️ ✔️ ✔️ ✔️
UNION ALL 合并结果,保留重复 ❌(保持原顺序) ✔️ ✔️ ✔️ ✔️
INTERSECT 取多个查询交集(都存在的行) ✔️ ✔️ ✔️
EXCEPT / MINUS 差集(第一查询有、后续没有的行) ❌(可用 NOT EXISTS 替代) EXCEPT ✔️ EXCEPT ✔️ MINUS ✔️

🔔 MySQL 不支持 INTERSECTEXCEPT,需用 INNER JOIN / NOT EXISTS 模拟(后文给出方案)。


二、UNIONUNION ALL

基本规则

  1. 列数必须相同
  2. 对应列数据类型需兼容(如 INT + VARCHAR 可能隐式转换);
  3. 结果集列名取自第一个查询
  4. 每个 SELECT 可独立使用 WHEREGROUP BYHAVING,但不能单独用 ORDER BY(除非加括号+LIMIT)

示例:合并销售数据(按季度分表)

1
2
3
4
5
6
7
8
9
10
11
12
-- 合并 Q1、Q2 销售记录,去重(如避免重复录入)
SELECT product, amount, 'Q1' AS quarter
FROM sales_q1
WHERE amount > 1000

UNION -- ← 自动去重 + 排序

SELECT product, amount, 'Q2'
FROM sales_q2
WHERE amount > 1000

ORDER BY amount DESC; -- 全局排序

UNION ALL 高性能场景

1
2
3
4
5
6
-- 日志按天分表,合并最近3天(无需去重)
SELECT * FROM log_20251206
UNION ALL
SELECT * FROM log_20251207
UNION ALL
SELECT * FROM log_20251208;
  • ⚡ 比 UNION 快 5~10 倍(省去排序+去重开销);
  • 适合:分区表合并、ETL 临时表整合、大数据分析。

✅ 三、交集 INNER JOININ

1
2
3
4
5
6
7
8
-- 方案1:INNER JOIN(推荐,性能好)
SELECT v.user_id
FROM vip_users v
INNER JOIN active_users a ON v.user_id = a.user_id;

-- 方案2:IN + 子查询
SELECT user_id FROM vip_users
WHERE user_id IN (SELECT user_id FROM active_users);

四、差集 NOT EXISTS

1
2
3
4
5
SELECT r.user_id
FROM registered_users r
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = r.user_id
);

避免用 NOT IN(若 orders.user_idNULL,结果为空!)


✅ 五、高级技巧与注意事项

1️ 为每个来源打标签

1
2
3
4
SELECT name, email, 'internal' AS source FROM employees
UNION ALL
SELECT name, email, 'external' FROM partners
ORDER BY source, name;

2️ 处理列类型不一致

1
2
3
4
5
6
7
8
9
-- 错误:INT vs VARCHAR
SELECT id FROM table1
UNION
SELECT name FROM table2; -- 可能报错或隐式转换失败

-- 正确:显式转换
SELECT CAST(id AS CHAR) FROM table1
UNION
SELECT name FROM table2;

3️ 子查询中使用 UNION

1
2
3
4
5
6
7
SELECT *
FROM (
SELECT id, name FROM students
UNION ALL
SELECT id, name FROM teachers
) AS all_people
WHERE name LIKE '张%';

4️ ORDER BY 限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--  错误:不能在中间 SELECT 加 ORDER BY
SELECT * FROM t1 ORDER BY id
UNION ALL
SELECT * FROM t2;

-- 正确1:全局排序
(SELECT * FROM t1)
UNION ALL
(SELECT * FROM t2)
ORDER BY id;

-- 正确2:各子查询排序+LIMIT(需括号)
(SELECT * FROM t1 ORDER BY id LIMIT 5)
UNION ALL
(SELECT * FROM t2 ORDER BY id DESC LIMIT 5);

六、性能优化建议

场景 建议
大结果集合并 优先用 UNION ALL,避免无意义去重
需去重但数据量大 UNION ALL + 外层 DISTINCT,或用 GROUP BY
多表 UNION 确保各 SELECTWHERE 条件能走索引
分页合并 外层分页,而非每个子查询分页(否则逻辑错)

约束

主键

  1. 主键列的值不能重复 PRIMARY KEY
  2. 值不能为NULL
  3. 可以复合,但必须唯一
  4. DESC 会显示主键

UNIQUE

被添加的值不能重复

外键

1
FOREIGN KEY (外键) REFERENCES table (属性)
  1. 外键类型与主键要一致
  2. 外键指向主键或UNIQUE
  3. 外键字段的值,必须出现在主键中,或为空
  4. 建立主外键关系后,数据不能随意删除

check

MySQL5.7不支持,只做语法校验

自增长

AUTO_INSERT

  • 自增长默认从1开始,但可修改
  • 通常搭配主键或UNIQUE

索引

MySQL 索引底层结构:B+ 树

MySQL 默认(InnoDB 引擎)使用 B+ 树(B+ Tree) 实现索引,不是哈希,也不是普通二叉树

B+ 树特点(InnoDB):

特性 说明
多路平衡查找树 每个节点可存多个 key,树高度低(通常 3~4 层可存千万级数据)→ 减少磁盘 IO
非叶子节点只存 key 不存数据,只存索引导航信息,单页可存更多 key,树更矮
叶子节点存完整数据(聚簇索引)或 主键值(二级索引) 叶子节点之间用双向链表连接 → 利于范围查询、排序
数据按 key 顺序存储 插入时可能分裂节点,但查询效率稳定

示意图简化版

1
2
3
4
5
              [20, 50]               ← 根节点(内存中常驻)
/ | \
[5,10,15] [25,30,40] [55,60,70] ← 非叶子节点
/ | | \ / | | \ / | | \
[1..5]...[15..20] ... [70..∞] ← 叶子节点(存数据或主键),双向链表连接

知识点:

  • 一次查询 = 树的高度次磁盘 IO(例如 3 层 → 3 次 IO);
  • 全表扫描 = 扫所有叶子节点(数据页);
  • 范围查询(如 WHERE id BETWEEN 10 AND 30)只需在叶子节点链表上顺序遍历,效率高。

MySQL 索引类型(按存储 & 逻辑分)

1️ 按存储结构分(InnoDB 引擎)

类型 中文名 说明 是否必须?
Clustered Index 聚簇索引 叶子节点直接存储整行数据。每个表只能有一个(因为数据只能按一种顺序物理存储)。InnoDB 中,主键就是聚簇索引 ✅ 是(无主键时,InnoDB 隐式创建 6 字节 row_id 作聚簇索引)
Secondary Index 二级索引(辅助索引) 叶子节点只存索引列 + 主键值。查数据时需“回表”(先查二级索引 → 拿主键 → 再查聚簇索引)。 ❌ 按需创建

举例(表:users(id PK, name, age)

  • 聚簇索引:按 id 组织数据页 → 查 WHERE id=100 → 1 次 IO 直接得数据。
  • 二级索引 idx_name (name)
    • 叶子节点存 (name, id)
    • WHERE name='Alice' → 先在 idx_name 找到 'Alice', id=500 → 再用 id=500 回表查聚簇索引 → 2 次 IO(即“回表”)。

优化技巧:覆盖索引(Covering Index)
如果查询的列全部包含在索引中,就无需回表!

1
2
3
4
5
-- 创建联合索引 (name, age)
CREATE INDEX idx_name_age ON users(name, age);

-- 查询只涉及 name 和 age → 直接从索引取数据,不回表!
SELECT name, age FROM users WHERE name = 'Alice';

2️ 按逻辑功能分(常用)

类型 语法 特点 适用场景
主键索引(PRIMARY KEY) PRIMARY KEY (id) 唯一、非空、聚簇索引 每表必有(显式或隐式)
唯一索引(UNIQUE) UNIQUE KEY (email) 值唯一(可 NULL,但只能一个 NULL) 身份证号、邮箱等唯一字段
普通索引(INDEX / KEY) INDEX idx_age (age) 无限制,可重复、可 NULL 高频查询字段(如状态、分类)
联合索引(Composite Index) INDEX idx_a_b_c (a, b, c) 多列组合,最左前缀原则生效 组合查询(如 WHERE a=? AND b=?
前缀索引 INDEX idx_url (url(20)) 只索引字符串前 N 字符,省空间 长文本(URL、描述),但可能降低区分度
全文索引(FULLTEXT) FULLTEXT (content) 支持 MATCH ... AGAINST 模糊搜索 文章内容、评论搜索(MyISAM / InnoDB ≥ 5.6)
空间索引(SPATIAL) SPATIAL INDEX (geom) 用于地理数据(POINT, POLYGON) GIS 应用

联合索引 & 最左前缀原则(面试高频!)

这是高效使用索引的关键

规则:

对联合索引 (a, b, c)

  • WHERE a = 1用索引
  • WHERE a = 1 AND b = 2用索引
  • WHERE a = 1 AND b = 2 AND c = 3用索引
  • WHERE a = 1 AND c = 3只用到 a(b 跳过,c 无效)
  • WHERE b = 2索引失效
  • WHERE c = 3索引失效
  • WHERE a = 1 AND b > 2 AND c = 3用到 a, b(c 无法用,因 b 是范围查询)

原理:B+ 树先按 a 排序,a 相同再按 b,再按 c
就像字典:先按首字母(a),再按第二字母(b)…… 要查“apple”,必须从 ‘a’ 开始;若直接查“pple”,无法定位。

正确建联合索引顺序:

1
2
3
4
5
6
7
8
-- 查询常为:WHERE status = 'active' AND create_time > '2024-01-01' ORDER BY user_id
-- 好顺序:(status, create_time, user_id)
-- 理由:
-- status = 常量 → 精准定位
-- create_time > 范围 → 可继续用索引范围扫描
-- user_id → 用于 ORDER BY,避免 filesort

CREATE INDEX idx_status_time_user ON orders(status, create_time, user_id);

如何判断索引是否生效?——EXPLAIN

这是调试索引的必备工具

1
EXPLAIN SELECT * FROM users WHERE name = 'Alice';

重点关注字段:

说明
type 访问类型:system > const > eq_ref > ref > range > index > ALL(越靠左越好,ALL=全表扫描)
key 实际使用的索引名
key_len 使用的索引长度(可判断联合索引用到几列)
rows 预估扫描行数(越少越好)
Extra 额外信息:
Using index → 覆盖索引(不回表)
⚠️ Using filesort → 内存/磁盘排序(慢)
⚠️ Using temporary → 用了临时表(慢)

示例:

1
2
EXPLAIN SELECT name, age FROM users WHERE name = 'Alice';
-- 若 key = idx_name_age, Extra = "Using index" → 完美覆盖索引!

索引失效的常见场景(避坑指南!)

场景 原因 解决方案
对字段做函数/运算 WHERE YEAR(create_time) = 2024 改写为范围:WHERE create_time BETWEEN '2024-01-01' AND '2024-12-31'
隐式类型转换 WHERE phone = 13800138000(phone 是 VARCHAR) 加引号:WHERE phone = '13800138000'
隐式字符集转换 关联字段字符集/排序规则不同 统一 CHARSETCOLLATE
LIKE 以通配符开头 WHERE name LIKE '%Alice%' 改用全文索引 / 模糊搜索中间件(Elasticsearch)
OR 条件未全覆盖索引 WHERE a=1 OR b=2(只有 a 有索引) UNION 拆分,或给 b 也加索引
不满足最左前缀 WHERE b=2(联合索引 (a,b) 调整索引顺序或建单列索引
数据区分度低 gender(只有 男/女)建索引 通常不建(除非配合其他列联合)

索引设计最佳实践(总结清单)

  1. 主键首选自增 INT/BIGINT
    → 避免 UUID 乱序插入导致页分裂(如需分布式 ID,用雪花算法 + 前移时间位)。

  2. 高频 WHERE / JOIN / ORDER BY 字段建索引
    → 先用 slow query logEXPLAIN 找慢查询。

  3. 优先考虑联合索引
    → 避免单列索引过多;按“等值在前,范围在后,排序最后”排序列。

  4. 善用覆盖索引
    SELECT 的列尽量包含在索引中,减少回表。

  5. 定期检查无效索引

    1
    2
    -- MySQL 5.7+:查看未使用的索引(需开启 performance_schema)
    SELECT * FROM sys.schema_unused_indexes;

    删除不用的索引,提升写性能。

  6. 大表加索引用 ALGORITHM=INPLACE(Online DDL)

    1
    2
    3
    ALTER TABLE users 
    ADD INDEX idx_name (name),
    ALGORITHM=INPLACE, LOCK=NONE; -- MySQL 5.6+ 支持,不锁表!
  7. 监控索引效率

    1
    SHOW INDEX FROM users;  -- 查看索引 Cardinality(区分度),越高越好

事务

用于保证数据的一致性,要么全部成功,要么全部失败。

概念

场景:用户 A 给用户 B 转账 100 元

1
2
3
4
5
-- 步骤1:A 扣款
UPDATE accounts SET balance = balance - 100 WHERE user = 'A';

-- 步骤2:B 收款
UPDATE accounts SET balance = balance + 100 WHERE user = 'B';

问题
如果步骤1成功,但步骤2因断电/崩溃失败 → A 少了 100,B 没收到 → 数据不一致!

事务的使命:把多个操作打包成一个“原子单元”,要么全成功,要么全失败回滚,绝不留半截状态!

1
2
3
4
5
6
7
START TRANSACTION;  -- 开启事务

UPDATE accounts SET balance = balance - 100 WHERE user = 'A';
UPDATE accounts SET balance = balance + 100 WHERE user = 'B';

COMMIT; -- 全部成功 → 永久生效
-- 或 ROLLBACK; -- 任一失败 → 撤销所有修改

设置保存点

1
2
SAVEPOINT A
ROLLBACK A (不具体指向默认回退到初始点)

事务的四大特性:ACID

字母 全称 含义 MySQL 如何保证
A Atomicity(原子性) 事务是最小单位,不可分割:要么全做,要么全不做 通过 Undo Log(回滚日志) 实现回滚
C Consistency(一致性) 事务前后,数据库从一个合法状态转移到另一个合法状态(如约束、触发器、业务规则仍成立) 由 A + I + D 共同保障 + 应用逻辑
I Isolation(隔离性) 多个事务并发执行时,互不干扰(如同串行执行) 通过 锁(Locking) + MVCC(多版本并发控制) 实现
D Durability(持久性) 事务一旦提交,结果永久保存(即使宕机也不丢) 通过 Redo Log(重做日志) + fsync 写入磁盘

关键理解

  • ACID 不是 MySQL “发明”的,而是事务的设计目标
  • InnoDB 引擎通过 WAL(Write-Ahead Logging) + Undo/Redo Log 实现 ACID;
  • MyISAM 不支持事务!务必用 InnoDB

事务隔离级别(解决并发问题)

多个事务同时操作数据,可能引发 3 类经典问题:

问题 描述 举例
脏读(Dirty Read) 读到未提交的中间数据 T1 改余额为 900(未提交)→ T2 读到 900 → T1 回滚 → T2 依据错误数据决策
不可重复读(Non-Repeatable Read) 同一事务内,多次读同一行,结果不同(被别人改了) T1 两次读 A 余额:第一次 1000 → T2 提交修改为 900 → T1 第二次读得 900
幻读(Phantom Read) 同一事务内,多次查同一范围,结果行数不同(被别人插入/删除) T1 SELECT * FROM orders WHERE amount > 100 得 5 行 → T2 插入一条 150 的订单 → T1 再查得 6 行

MySQL 的 4 种隔离级别(InnoDB 默认:REPEATABLE READ

隔离级别 脏读 不可重复读 幻读 实现方式 性能
READ UNCOMMITTED ❌ 允许 ❌ 允许 ❌ 允许 几乎无锁 ⚡ 最快
READ COMMITTED ✅ 禁止 ❌ 允许 ❌ 允许 行锁 + MVCC(每次读取最新已提交版本)
REPEATABLE READ(MySQL 默认) ⚠️ InnoDB 用 MVCC + 间隙锁基本解决 MVCC + Next-Key Lock(行锁+间隙锁)
SERIALIZABLE 所有读加共享锁,串行执行 最慢

🔍 重点:InnoDB 的 RR 级别如何防止幻读?

  • 快照读(普通 SELECT):通过 MVCC 读事务开始时的一致性视图,天然无幻读;
  • 当前读(SELECT … FOR UPDATE / LOCK IN SHARE MODE / UPDATE / DELETE):通过 Next-Key Lock(锁住记录 + 前后间隙)防止新记录插入。
1
2
3
4
-- 当前读示例:防止别人在 (100, 200) 之间插新订单
SELECT * FROM orders
WHERE amount > 100 AND amount < 200
FOR UPDATE; -- 加 Next-Key Lock

事务控制语句(实战语法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 1. 开启事务(显式)
START TRANSACTION;
-- 或
BEGIN;

-- 2. 执行 SQL(DML:INSERT/UPDATE/DELETE)
UPDATE accounts SET balance = balance - 100 WHERE user = 'A';
INSERT INTO transfers (from_user, to_user, amount) VALUES ('A', 'B', 100);

-- 3. 提交 or 回滚
COMMIT; -- 永久生效
-- ROLLBACK; -- 撤销所有修改(到 START TRANSACTION 之前)

-- 4. 设置保存点(部分回滚)
SAVEPOINT sp1;
UPDATE ...;
ROLLBACK TO sp1; -- 只回滚到 sp1,之前的操作仍保留

注意:

  • DDL(如 CREATE TABLE)、LOCK TABLES隐式提交当前事务;
  • 客户端自动提交模式:
    1
    2
    SELECT @@autocommit;  -- 1=开启(每条 SQL 自动 COMMIT),0=关闭
    SET autocommit = 0; -- 关闭自动提交,需手动 COMMIT

InnoDB 事务实现原理(深入理解)

核心组件:

组件 作用
Undo Log 存储修改前的旧值 → 用于回滚(ROLLBACK)和 MVCC 快照读
Redo Log 存储修改后的物理日志 → 崩溃恢复时重做(保证 Durability)
Write-Ahead Logging:先写日志,再写数据页
Read View 事务开启时生成的“一致性视图” → 决定能看到哪些版本的数据(MVCC 关键)
Next-Key Lock 行锁(Record Lock) + 间隙锁(Gap Lock) → 防止幻读

事务执行流程(简化):

  1. START TRANSACTION → 生成 Read View
  2. 执行 UPDATE
    • 修改 Buffer Pool 中的数据页;
    • Undo Log(旧值);
    • Redo Log Buffer(新值);
  3. COMMIT
    • Redo Log Buffer 刷盘(fsync)→ 事务持久化
    • 释放锁;
  4. 后台线程异步刷脏页到磁盘。

崩溃恢复:重启时,InnoDB 用 Redo Log 重做已提交事务,用 Undo Log 回滚未提交事务。


事务使用最佳实践 & 常见误区

推荐做法:

场景 建议
短事务 尽量缩短事务时间(避免 BEGIN 后做耗时计算/网络请求)→ 减少锁竞争
小批量提交 大量 INSERT/UPDATE 分批提交(如每 1000 行 COMMIT 一次)→ 防止 Undo Log 暴胀
明确隔离级别 按需设置(如报表用 READ COMMITTED,金融用 REPEATABLE READ):
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
异常处理 代码中捕获异常 → 显式 ROLLBACK(避免连接池残留未提交事务)
避免长事务 监控 information_schema.INNODB_TRX,杀掉长时间未提交事务

常见错误:

误区 后果 正确做法
BEGIN 后不 COMMIT/ROLLBACK 连接一直占着锁 → 阻塞其他事务 try-catch-finally 确保提交/回滚
在事务中调用外部 API 事务长时间挂起 → 锁超时、连接池耗尽 先提交事务 → 再调外部服务(用消息队列解耦)
默认隔离级别下误以为无幻读 当前读(FOR UPDATE)仍可能见幻读 理解 MVCC vs 当前读区别;必要时显式加锁
大事务导致主从延迟 Redo Log 太多,从库追不上 分批提交 + 并行复制

如何监控事务?

1
2
3
4
5
6
7
8
9
-- 1. 查看当前运行的事务(重点关注 trx_state, trx_started)
SELECT * FROM information_schema.INNODB_TRX;

-- 2. 查看锁等待
SELECT * FROM sys.innodb_lock_waits;

-- 3. 查看长事务(运行超过 60 秒)
SELECT * FROM information_schema.INNODB_TRX
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;

存储引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SHOW ENGINES

mysql> SHOW ENGINES;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears)| NO | NO | NO |
| MyISAM | YES | Non-transactional engine with good read performance | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Compression-focused storage engine for archival data | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine (not available in 8.0+) | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
  • Support:DEFAULT = 默认引擎;YES = 支持但非默认;NO = 编译支持但禁用;DISABLED = 不支持
  • Transactions:是否支持事务(YES = 事务安全型;NO = 非事务安全型)
  • XA:是否支持分布式事务(XA 协议)
  • Savepoints:是否支持保存点(SAVEPOINT / ROLLBACK TO)

事务安全型

InnoDB(MySQL 5.5+ 默认引擎)

特性 说明
事务支持 ACID 全满足(靠 Undo Log + Redo Log + MVCC)
行级锁 并发写入性能高(MyISAM 是表锁)
外键约束 FOREIGN KEY 支持(数据完整性保障)
崩溃恢复 重启自动恢复,数据不丢失
MVCC 多版本并发控制,高并发读写无阻塞
全文索引 MySQL 5.6+ 支持(FULLTEXT
数据压缩 支持页压缩(节省磁盘)

非事务安全型

引擎 特点 适用场景 ⚠️ 主要缺陷
MyISAM • 表级锁(写阻塞读)
• 查询快(尤其 COUNT(*))
• 支持全文索引(旧版)
• 不支持事务/外键
• 只读报表库
• 日志归档(极少更新)
• 低频读、无并发写场景
• 崩溃后需手动修复(myisamchk
• 写入时全表锁 → 高并发下性能差
• 无崩溃恢复 → 可能丢数据
MEMORY • 数据全在内存
• 哈希/ B树索引
• 极快读写
• 临时缓存表
• 会话级临时数据
• 小型维度表
• 重启数据全丢
• 不支持 BLOB/TEXT
• 内存有限,易 OOM
CSV • 数据存为 CSV 文件
• 可直接用文本工具编辑
• 数据导入导出中转
• 与外部系统交换数据
• 无索引
• 不支持 NULL
• 全表扫描
ARCHIVE • 高压缩比(zlib)
• 只支持 INSERT / SELECT
• 日志、审计、历史归档(只追加不更新) • 无索引(全表扫描)
• 不支持 DELETE/UPDATE
BLACKHOLE • 写入即丢弃(/dev/null • 主从复制中“过滤”数据
• 压测写入吞吐
• 数据不持久化


如何查看/设置表的存储引擎?

1. 查看某张表的引擎:

1
2
3
4
SHOW CREATE TABLE users;  -- 看 CREATE 语句末尾的 ENGINE=...
-- 或
SELECT ENGINE FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'users';

2. 建表时指定引擎:

1
2
3
4
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
amount DECIMAL(10,2)
) ENGINE = InnoDB; -- 显式指定(推荐)

3. 修改已有表的引擎(谨慎!大数据量会锁表):

1
2
ALTER TABLE old_myisam_table ENGINE = InnoDB;
-- ⚠️ 大表建议用 pt-online-schema-change 工具在线转换

选择存储引擎决策树

1
2
3
4
5
6
7
8
9
10
11
12
graph TD
A[需要事务/外键/崩溃恢复?]
-->|是| B[选 InnoDB]
A -->|否| C{主要是读?写很少?}
C -->|是| D{需要极快 COUNT* 或全文检索(旧版)?}
D -->|是| E[考虑 MyISAM]
D -->|否| F{数据临时/内存足够?}
F -->|是| G[MEMORY]
F -->|否| H{只追加不更新?需高压缩?}
H -->|是| I[ARCHIVE]
H -->|否| J[仍推荐 InnoDB]
C -->|否(高并发写)| B

终极建议
除非有非常明确的特殊需求(如 MEMORY 做缓存),否则一律用 InnoDB
它是 MySQL 社区和官方持续优化的重点,功能、稳定性、性能综合最佳。


附:InnoDB vs MyISAM 关键对比表

特性 InnoDB MyISAM
事务 ✅ ACID
锁粒度 行锁 表锁
外键
崩溃恢复 ✅ 自动 ❌ 需手动修复
全文索引 ✅(5.6+) ✅(但旧版)
COUNT(*) 慢(需扫描) 快(存了行数)
存储空间 稍大(存双写缓冲等)
适用场景 通用、高可靠 只读/低写

前言

在学习Spring Boot时了解到这是一个整合Web/持久层(持久层框架(如MyBatis/Hibernate)属于数据访问层组件,与Web框架是协作关系而非包含关系。)的全栈框架,但对于各种框架的含义仍缺乏了解,故在此系统梳理一下。

框架

定义

Java Web框架是封装好的专为构建Web应用的代码骨架,为开发者提供标准化的开发基础。在框架中预先写好了许多基础或底层功能,让开发者可以在开发时避免在这些琐碎的方面浪费时间,专心于业务逻辑和核心代码构建。

核心功能

1.提升开发效率。 框架可以通过调用接口等方式自动化处理如数据库操作、HTTP请求解析等重复性任务。

2.生态整合。 一些框架会集成数据库、缓存、消息队列等第三方组件,不需要开发者进行二次引入(SpringBoot自带Tomcat)。

3.提高维护性。 模块化设计降低代码耦合度,便于后期扩展。

分类

架构风格分类

1. 传统 MVC 框架

  • 代表框架: Spring MVC, Struts2 (已过时)
  • 特点: 基于 Servlet 规范,采用同步阻塞 I/O 模型。严格遵循 Model-View-Controller 分层设计,强调职责分离。通常配合 JSP、Thymeleaf 等模板引擎进行服务端渲染 (SSR)。
  • 适用于: 传统的企业级单体应用、后台管理系统、SEO 友好的门户网站。

2. 微框架 (Micro-frameworks)

  • 代表框架: Javalin, Spark Java, Blade
  • 特点: 极简设计 (核心库往往 <1MB),不强制特定的项目结构。去除了复杂的依赖注入和繁重的配置,专注于提供轻量级的 HTTP 路由和 API 处理。
  • 适用于: 轻量级微服务、简单的 RESTful API、原型快速开发、教学演示。

3. 云原生框架 (Cloud-Native)

  • 代表框架: Quarkus, Micronaut, Helidon
  • 特点: “为云而生”。通过编译时依赖注入 (Compile-time DI) 和 AOT (Ahead-of-Time) 预编译技术,显著减少内存占用和启动时间。完美适配 Kubernetes 环境,且对 GraalVM 原生镜像有极佳支持。
  • 适用于: Serverless (无服务器架构)、高密度部署的容器化微服务、对启动速度和内存有严格要求的场景 (如 AWS Lambda)。

4. 响应式框架 (Reactive)

  • 代表框架: Spring WebFlux, Vert.x
  • 特点: 基于 Netty 等非阻塞服务器,采用异步非阻塞 I/O 模型和事件驱动架构。能够以少量的线程处理极高的并发请求,背压 (Backpressure) 机制保证系统稳定性。
  • 适用于: 高并发系统 (如网关、社交 IM)、I/O 密集型应用、实时数据流处理。

按部署形态分类

1. 嵌入式服务器框架

  • 代表: Spring Boot
  • 形态: 内嵌 Tomcat/Jetty/Undertow(4里取消支持Undertow了,不知道未来会不会支持,先插个眼) 容器。
  • 特点: 打包为可执行的 Fat JAR,java -jar 即可运行,不再依赖外部 Web 容器。
  • 性能: 启动时间通常在 1-5 秒,开发体验极佳。

2. GraalVM 原生框架

  • 代表: Quarkus Native, Micronaut Native
  • 形态: 经 GraalVM 编译为本地机器码 (Binary)。
  • 特点: 启动速度极快 (<50ms),内存占用极低 (<30MB),但构建 (Build) 时间较长,且反射机制受限。
  • 性能: “冷启动”几乎消失,非常适合 Serverless。

3. 传统 WAR 部署框架

  • 代表: JSF + WebLogic/JBoss
  • 形态: 打包为 WAR 文件,需部署到独立的外部应用服务器中。
  • 特点: 配置繁琐,依赖服务器环境,且应用服务器本身启动沉重。
  • 现状: 主要存在于遗留系统 (Legacy Systems) 中,新项目已很少采用。

引入

之前跟着教程做了web后端的项目,打算找个时间上线运营培养经验,不过因为域名的问题一直拖着没做。

但在学习网络安全时,老师提了一句:“为什么不用MD5加密,因为它已经被破解了”,一句话让我的困意瞬间消失。因为我的加密就是用MD5。

MD5为什么不能用

MD5的加密逻辑

将输入数据扩展为 512 位的整数倍,用四个 32 位的十六进制整数作为初始链接变量进行四轮循环运算,每轮循环包含 16 次操作,共 64 步。每轮循环结束后,将当前链接变量 A、B、C、D 分别加上临时变量 a、b、c、d。最终,将四个链接变量级联,得到 128 位的 MD5 哈希值。

缺点

1.计算太快

对于选择的电脑的性能,MD5的计算量太少,攻击者可以轻松通过计算进行解密。

2.被证明过不安全

王小云研究团队发现了MD5国际密码算法存在漏洞,被证实MD5并不安全。

选择SpringSecurity的原因

优势

1.导入便捷

SpringSecurity 对于 SpringBoot 项目来说几乎是“标配安全框架”,只需要在pom.xml文件中加入配置就可以进行使用。

2.自带BCrypt,加密安全

BCrypt是慢哈希函数,适合存储密码,带 salt,不可逆,抗暴力破解。

3.内置认证 + 授权体系

Security会自己处理:登录验证、过滤器链、会话安全、跨域、csrf、路由权限控制等问题,开发者不需要操心这些方面的问题。

配置和导入

1.依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 配置类

补充:之前没注意Spring2和Spring3的区别

Spring Boot 2.x 配置方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
}

作者:刘大华
链接:https://juejin.cn/post/7570191839593332799

来源:稀土掘金

SpringBoot 3 去掉了 WebSecurityConfigurerAdapter,用 Bean 配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register").permitAll()
.anyRequest().authenticated()
)
.formLogin(login -> login
.loginPage("/login")
.permitAll()
);
return http.build();
}
}

如何兼容之前的用户

之前在数据库中存储的密码是MD5加密的,如果直接更新加密方法,会导致之前的用户无法登录。所以需要增加一段逻辑。

用户注册->直接使用SpringSecurity加密。

用户登录->如果使用MD5加密:用MD5验证->更新加密逻辑,将新的数据存入数据库。

为什么要学沙箱

第一次接触这个概念是因为Python的期末大作业,老师让我们写一个python学习的平台。

我想到模仿FreeCodecamp,写一个可以通过程序二次运行python代码的平台。

之前也没有相关的经验,我便将自己的想法发给ai,让它告诉我需要用到什么,也就接触到了沙箱–用于防止别人在执行代码时对程序(或电脑)造成破坏。

概念

沙箱(Sandboxing)是一种用于隔离环境的技术。

用途

沙箱技术通常用于以下几类场景:

  • 在线代码运行平台:如 LeetCode、FreeCodeCamp、自建 OJ 系统
  • 浏览器隔离:Chrome 的每个 tab 页就是一个沙箱进程
  • 移动端应用权限管理:iOS、Android 对 App 的文件访问就是沙箱设计
  • 恶意软件分析:将样本放在沙箱中运行,观察行为
  • 插件系统:比如浏览器扩展、VSCode 插件,都不能直接访问用户系统
  • 安全研究和渗透测试有专门做沙箱业务的公司

这些场景的共同点就是:“运行不可信代码”,而沙箱的职责就是“让它尽量跑得动,但伤不到我”。

分类

根据隔离程度不同,可以粗略分成三类:

1. 语言级沙箱(最轻量)

依赖语言本身的机制进行限制。

  • Python 的 ast、受控 namespace
  • JavaScript 的 vm2
  • Lua 沙箱化 runtime

优点:实现简单,启动快
缺点:很容易被绕过,安全性弱

2. 系统级沙箱(中等级别)

依赖操作系统提供的隔离机制:

  • Linux cgroups(限制资源)
  • namespace(隔离进程、文件系统、网络)
  • seccomp(限制系统调用)
  • Docker / LXC(容器)

优点:安全性高、性能好
缺点:实现较复杂,需要系统层面的支持

3. 虚拟化级沙箱(最高隔离)

原来我用过这么久沙箱…

  • KVM
  • QEMU
  • Firecracker(AWS Lambda 用的)
  • VirtualBox

优点:隔离性能好
缺点:启动慢、消耗资源大,不适合大量高频的代码执行

实现模板

Java

java.lang.SecurityManager是Java的一个可插拔的安全策略执行器,用于在运行时对敏感操作(如文件读写、网络访问、反射调用、类加载等)进行权限检查。

当某段代码执行特权操作时,JVM 会调用 SecurityManager.checkXXX() 方法(如 checkRead, checkConnect, checkPermission 等),若未授权,则抛出 SecurityException。

虽然“安全管理员多年来一直不是保护客户端 Java 代码的主要手段,也很少用于保护服务器端代码,并且维护成本很高。”(官方回复),导致这个类在JDK17后被淘汰了,但作为新手去学习依旧足够了。

Python

目前还在写(前文提到的),先插个眼

TODO

一些开源的沙盒项目

https://github.com/sandboxie-plus/Sandboxie Sandboxie 允许您创建几乎无限的沙箱并单独或同时运行它们,以将程序与主机隔离并相互隔离,同时还允许您在单个盒子中同时运行任意数量的程序。

https://github.com/alibaba/jvm-sandbox
JVM-SANDBOX(沙箱)实现了一种在不重启、不侵入目标JVM应用的AOP解决方案。

起因

在我的项目中,用户注册后会获得默认头像。虽然后续可以自行更改,但未免太过单调。于是我便想起注册GitHub时,会根据用户的名称自动生成一个头像,还不用担心版权问题。于是我在项目中引入了头像生成工具,测试成功后分享给大家。

Dicebear

简介

Dicebear 是一个开源的头像生成服务,支持 SVG、PNG 等多种格式。
它的特色是:风格丰富、可定制项多、无需复杂后端即可直接使用。无论是像素风、卡通风,还是圆形首字母,都能一键生成。

更重要的是,Dicebear 是 MIT License,使用范围宽松,不存在版权风险。

导入

1. 直接请求 API(最简单)

1
https://api.dicebear.com/7.x/{style}/svg?seed={text}

例如:

https://api.dicebear.com/7.x/bottts/svg?seed=darkyellowcat

返回的就是一个 SVG 头像。

2. NPM 包

1
npm install @dicebear/core @dicebear/bottts

示例:

1
2
3
4
5
6
7
8
import { createAvatar } from '@dicebear/core';
import { bottts } from '@dicebear/bottts';

const avatar = createAvatar(bottts, {
seed: 'darkyellowcat'
});

const svg = avatar.toString();

功能

支持十几种风格(像素、商务、卡通、漫画…)

支持通过 seed 保证「同名用户头像固定」

提供性别随机化、配色方案、表情样式等配置

可直接返回 SVG 或 PNG

CDN 快速访问,不占用自己服务器

ui-avatars

简介

ui-avatars是一个简单、轻量的姓名首字母头像生成工具。(GMail的用户头像就是单字母)

它不支持复杂的风格,但胜在简单、稳定、无需依赖库,访问速度快。

导入

只需直接请求 API:

1
https://ui-avatars.com/api/?name={Name}&background=random

例如:

1
https://ui-avatars.com/api/?name=Dark+Bird&background=random

返回的是 PNG 图片。

功能

不需要 seed,直接根据名称生成

配置参数简单易懂

轻量、稳定、无额外依赖

不会出现风格过于跳脱的问题

对比

ui-avatars相较而言功能较少,仅通过名称生成首字母头像,风格和种类较少。

但风格单一换来的是,它几乎不需要学习成本,且更加轻量级,适合喜欢简约风或轻量化配置的用户。

当然,你也可以在配置中同时引入两种工具,根据情况选用。

1-Maven介绍

1.1 Maven两大功能

1.1.1 项目构建

Maven构建项目特点:

Maven可以将传统的项目构建标准化,每个阶段用一个命令完成。

1、Clean 生命周期:

clean:删除目标目录中的编译输出文件。这通常是在构建之前执行的,以确保项目从一个干净的状态开始。

2、Default 生命周期(也称为 Build 生命周期):

validate:验证项目的正确性,例如检查项目的版本是否正确。

compile:编译项目的源代码。

test:运行项目的单元测试。

package:将编译后的代码打包成可分发的格式,例如 JAR 或 WAR。

verify:对项目进行额外的检查以确保质量。

install:将项目的构建结果安装到本地 Maven 仓库中,以供其他项目使用。

deploy:将项目的构建结果复制到远程仓库,以供其他开发人员或团队使用。

3、Site 生命周期:

site:生成项目文档和站点信息。

deploy-site:将生成的站点信息发布到远程服务器,以便共享项目文档。

alt text

与其他项目构建工具对比

1.Ant:Ant没有依赖管理功能.

2.Gradle:在Maven Apache的基础上引入了基于Groovy的特定领域语言。

1.1.2依赖管理

传统

手动拷贝jar包

1.容易版本冲突;
2.难以寻找;
3.添加麻烦。

Maven

在pom.xml文件中添加jar包坐标,Maven会自动从仓库中下载
1.一步构建;

2.方便管理;

3.支持跨平台。

2-Maven仓库

2.1 本地仓库

本地仓库,在第一次执行 maven 命令的时候才被创建。

运行 Maven 的时候,Maven 所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。

默认情况下,不管 Linux 还是 Windows,每个用户在自己的用户目录下都有一个路径名为 .m2/repository/ 的仓库目录。

2.2 远程仓库

2.2.1 中央仓库

中央仓库是由 Maven 社区提供的仓库,其中包含了大量常用的库。
https://repo.maven.apache.org/maven2/

2.2.2 私服仓库

局域网架设私有仓库服务器,常用于企业开发。

2.3 替换仓库至阿里云

中央仓库的服务器在国外,国内进行访问下载速度较慢,可以替换为阿里云的镜像仓库。

修改 maven 根目录下的 conf 文件夹中的 settings.xml 文件,在 mirrors 节点上,添加内容如下:

1
2
3
4
5
6
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>

如果想使用其它代理仓库,可在 节点中加入对应的仓库使用地址。以使用 spring 代理仓为例:

1
2
3
4
5
6
7
8
9
10
<repository>
<id>spring</id>
<url>https://maven.aliyun.com/repository/spring</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>

3-核心文件pom.xml

3.1 示例文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- Maven模型版本-->
<modelVersion>4.0.0</modelVersion>
<!--组织标识-->
<groupId>com.darkyellowcat</groupId>
<!--项目标识-->
<artifactId>untitled</artifactId>
<!-- 版本号-->
<version>1.0-SNAPSHOT</version>
<!-- 项目依赖-->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--项目依赖-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<!-- 配置项-->
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>TomcatServer</server>
<path>/untitled</path>
</configuration>
</dependency>
</dependencies>

</project>

3.2 Maven坐标

Maven通过groupId,artifactId,version三个字段来获取坐标,进而获得jar包。

4-三大生命周期

官网
https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

4.1 clean清理项目

清理项目的临时文件和目录

1.pre-clean 清理前

2.clean

3.post-clean 清理后

命令

1
mvn clean

4.2 defalut项目构建

核心生命周期,负责项目构建和部署的所有核心步骤。

1
mvn validate/compile/test ...

4.3 site生成文档

1
mvn site

pre-site 生成前准备

site 生成项目站点文档

post-site 收尾

site-deploy 部署站点到服务器

5-依赖管理

5.1流程

pom.xml中添加地址 -> 在本地仓库中查找 -> 去远程仓库查找(如果有) -> 去中央仓库下载

5.2依赖传递

5.2.1 直接依赖和间接依赖

如果B使用A,C使用B,那么B是C的直接依赖,C是A的间接依赖。Maven 会自动将间接依赖引入,这种自动处理依赖关系的特性称为传递性依赖(Transitive Dependencies)。

5.2.2 影响

alt text
//本图来自菜鸟教程

5.2.3 依赖冲突

如果直接依赖和间接依赖同时包含一个包的不同版本,默认以直接依赖为准。
去除依赖:

1
2
3
4
5
6
7
8
<exclusions>
<groupId>
xxx
</groupId>
<artifactId>
xxx
</artifactId>
</exclusions>

6-插件

6.1 功能

插件用于用于执行特定任务(编译、测试、打包等),具体实现生命周期对应的功能。

6.2 绑定方式

Maven会为生命周期阶段预绑定插件,同时也支持在pom.xml中自定义绑定

补充:

推荐菜鸟教程,虽然直接点进去看起来有点乱,但知识点很全,也适合做笔记。
https://www.runoob.com/maven

前言

网上关于“MySQL密码正确却无法登录”的解决方案很多,比如跳过权限验证、重置 root 密码、检查插件认证方式等。但在我遇到的问题中,这些方法都不适用——因为根本不是密码错了,而是连错了实例
这里记录一下我的“乌龙”经历,希望能帮到踩了同样坑的朋友。

正文

情况描述

我在本地安装并配置好 MySQL 后,成功设置了 root 密码,并正常使用了一段时间。
但第二天再次尝试登录时,执行:

1
mysql -u root -p

却出现

1
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

于是按照网上的教程重置了密码,登录就成功了,我便没有深究。

然而,当我为了修改数据库默认编码(utf8mb4)而编辑 my.ini 文件并重启 MySQL 后,发现之前创建的数据库和表全都不见了!

病因分析

经过反复排查,终于发现问题根源:

我之前退出 MySQL 客户端时,直接关闭了命令行窗口,没有输入 exit 或 \q 正常退出。
第二天执行 mysql -u root -p 时,系统自动启动了一个新的、干净的 MySQL 实例(或连接到了另一个实例),而这个实例的 root 用户密码是空的(或默认值),和我之前配置的实例不是同一个!

更具体地说:

我本地可能同时存在两个 MySQL 服务

解决办法

1. 确认当前连接的是哪个 MySQL 实例

登录后执行:

1
SHOW VARIABLES LIKE 'datadir';

查看数据目录。对比你之前配置的 my.ini 中的 datadir 路径是否一致。

2. 检查 MySQL 服务状态

在 Windows 上:

1
2
3
sc query mysql
# 或
net start

看是否有多个 MySQL 服务在运行(如 MySQL80、MySQL 等)。

在 Linux/macOS 上:

1
ps aux | grep mysqld

3. 确保只启动一个 MySQL 服务

停止所有 MySQL 进程(把不是你需要的服务删除了),然后手动启动你配置过的那个实例:

Windows(以管理员身份)

1
2
net stop MySQL80
mysqld --defaults-file="C:\path\to\my.ini"

4. 使用明确的连接方式

如果你有多个实例,建议通过指定端口或 socket 连接:

1
mysql -u root -p -P 3306 --protocol=tcp

5. 避免“直接关窗口”

虽然直接关闭命令行通常不会导致数据丢失,
但介于我糟心的体验,还是建议养成输入 exit 退出的习惯。

bb

如果所有方法试过之后都不好用,重装可以解决你的一切烦恼(记得备份数据)。

引言

在 GitHub 上,我们经常会遇到一个共同的问题:项目结构太复杂,源码难以理解。而 DeepWiki 正是为了解决这个痛点而诞生的一个开源导航与推荐工具。它通过算法与人工整理相结合,帮助开发者快速解析 GitHub 项目、文档和资源。

正文

简介

DeepWiki 是一个聚焦于 GitHub 的“项目百科全书”,它从开源生态中自动抓取并解析优质项目,帮助开发者探索、学习与贡献。

它不仅仅是一个项目索引网站,更像是一个面向开发者的知识图谱平台,让你能在更短时间内发现优秀的轮子和前沿技术。

主要特点包括:

  • 操作简洁
  • 清晰的界面设计与标签导航
  • 高质量项目解析功能

核心功能

  1. 智能推荐
    DeepWiki 利用算法从 GitHub 数据中挖掘高活跃度、高质量的项目,避免信息噪声,让用户更容易发现真正值得关注的仓库。

  2. 项目百科页
    每个项目页面不仅展示仓库信息,还包含简明的技术介绍、相关项目推荐以及技术栈标签,帮助你快速了解一个项目的全貌。

  3. 主题导航与技术地图
    用户可以按主题(如“AI”、“Web”、“Database”、“Security”)浏览项目,形成知识体系化的视图,便于系统学习。

  4. 趋势追踪与时间线
    DeepWiki 追踪项目的活跃度与更新时间,提供类似“今日热门”、“本周上升榜”等趋势榜单,帮助开发者掌握社区动态。

使用指南

http://github.com替换http://deepwiki.com
列如:https://github.com/spring-projects/spring-framework -> https://deepwiki.com/spring-projects/spring-framework

alt text ->

alt text

总结

DeepWiki 是一个极具潜力的开源项目导航与探索平台,对于经常逛 GitHub 的开发者而言,它能大大理解成本,帮助你快速了解技术生态、发现优秀项目。

无论你是想找灵感、学习新框架,还是参与开源贡献,DeepWiki 都是一个不可错过的工具。

🌐 官方网站:https://deepwiki.org/

💡 适合人群:开发者、开源爱好者、学习者

🧭 一句话总结:让 GitHub 的知识图谱更清晰,让探索更高效。

缘由

在大学生活中,我发现很多同学虽然渴望社交,却苦于没有合适的渠道。传统的社交平台要么信息过载,要么匹配机制粗糙。于是,我萌生了开发 weconnected 的想法——一个让用户通过自定义标签(如“摄影”“考研”“Java后端”)快速找到志同道合伙伴的轻量级社交平台。

💡 项目初衷:降低高质量社交的门槛,让“找人”变得更精准、更自然。

项目概览

  • 核心功能
    • 用户注册/登录(含密码加密)
    • 自定义兴趣标签(可增删改)
    • 基于标签的用户匹配与展示
    • 简易个人主页
  • 技术栈
    • 后端:Spring Boot 3 + MyBatis + MySQL + Redis
    • 安全:盐值 + MD5 加密(可后续升级为 BCrypt)
    • 工具:Knife4j(API文档)、Lombok、Maven
    • 前端:Vue 3 + Vite + Vue Router + Axios(借助 CLI 脚手架 + AI 辅助)

后端设计亮点

1. 标签系统设计

  • 用户标签存储在表 user中,支持一对多关系。
  • 查询“相同标签用户”时,使用 SQL 的 JOIN 实现高效匹配。
  • 为提升性能,对高频查询(如热门标签用户列表)引入 Redis 缓存,设置合理过期时间。

2. 安全实践

  • 密码采用 盐值 + MD5 加密存储(说明:MD5 已不推荐用于生产,但作为学习项目可接受;后续可替换为 Spring Security + BCrypt)。

3. API 文档与调试

  • 集成 Knife4j,自动生成美观的 Swagger UI,方便前后端联调。

前端实现简述

由于我主要专注后端开发,前端借助 Vue 3 官方脚手架(Vite) 快速搭建,并使用 AI 工具辅助编写组件逻辑(如标签选择器、用户卡片渲染)。虽然界面较为简洁,但功能完整、交互流畅。

🙏 欢迎前端高手提 PR 或建议!项目开源地址:https://github.com/darkyellowcat/weconnected

遇到的挑战与收获

  • 挑战1:如何高效实现“标签匹配”?
    → 最初用全表扫描,性能差;后改用 Redis 缓存热门标签用户 ID 列表,QPS 提升明显。

  • 收获:完整走通一个全栈项目流程,加深了对 Spring Boot、Redis 缓存策略、RESTful API 设计的理解。

下一步计划

  • 引入 WebSocket 实现实时聊天
  • 用 Spring Security 重构认证模块
  • 添加单元测试(JUnit + Mockito)
  • 优化前端 UI/UX

结语

weconnected 不仅是一个技术练手项目,更是我对“技术如何解决真实问题”的一次尝试。如果你也在做类似的项目,欢迎交流!也欢迎 Star / Fork 项目,一起让它变得更好 🌟