跳到主要内容

创建日期:2026-09-08 | 最近更新:2026-09-08 本机 MySQL 8.4.0 实测;下方输出均为真实结果(自动递增 id 延续了此前测试数据,无关紧要)。

MySQL 复习 1:CRUD 与约束

会了增删改查 + 建表约束,你就能在绝大多数后端项目里「干活了」。CRUD = Create / Read / Update / Delete,对应四条 SQL。

1. 四个动词:INSERT / SELECT / UPDATE / DELETE

-- 增:指定列插一行
INSERT INTO customers (name, email, city) VALUES ('李雷', 'lilei@example.com', '深圳');

-- 查:挑列、过滤、排序、限量(用得最多)
SELECT id, name, city FROM customers
WHERE city = '上海'
ORDER BY id DESC
LIMIT 10;

-- 改:务必带 WHERE,否则全表都改!(高危)
UPDATE customers SET city = '广州' WHERE email = 'lilei@example.com';

-- 删:同样务必带 WHERE
DELETE FROM customers WHERE email = 'lilei@example.com';

三条保命习惯

  1. UPDATE/DELETE 先写 WHERE 再写别的;不确定就先用同条件 SELECT 看会命中几条;
  2. 联调/本地常开事务:BEGIN; …改…; 满意再 COMMIT,不满意 ROLLBACK(篇 4);
  3. 查询尽量只 SELECT 需要的列,别长期 SELECT *(篇 7 讲为什么)。

实测:一条龙的完整输出

INSERT INTO customers(name,email,city) VALUES('李雷','lilei@example.com','深圳');
SELECT id,name,city FROM customers WHERE email='lilei@example.com';
UPDATE customers SET city='广州' WHERE email='lilei@example.com';
SELECT id,city FROM customers WHERE email='lilei@example.com';
DELETE FROM customers WHERE email='lilei@example.com';
SELECT COUNT(*) total FROM customers;
+-----+--------+--------+
| id | name | city |
+-----+--------+--------+
| 514 | 李雷 | 深圳 |
+-----+--------+--------+
+-----+--------+
| id | city |
+-----+--------+
| 514 | 广州 |
+-----+--------+
+-------+
| total |
+-------+
| 300 |
+-------+

关键点:idAUTO_INCREMENT 自增主键,你 INSERT 不用填,数据库自动给 514;UPDATE 后同一条记录 city 变了;DELETE 后 COUNT(*) 回到 300。

2. 主键(PRIMARY KEY):每行的「身份证」

  • 建表时指定:id BIGINT AUTO_INCREMENT PRIMARY KEY
  • 作用:唯一标识一行 + 查询/关联用它(底层自动建主键索引,篇 3);
  • 好主键的三个标准:不变、唯一、尽可能短(自增整数最省心;UUID 短字符串也可但要考虑性能)。

3. 常用约束一览(建表时给自己「上规矩」)

约束作用违反时的结果
PRIMARY KEY唯一 + 非空 + 主索引重复/为空 → 报错
UNIQUE该列值不许重复(可空,但空只能一个)重复 → 报错 1062
NOT NULL不许为空插入空 → 报错
DEFAULT 值不填时用默认值
CHECK (条件)值域检查(8.0 起真生效)不满足 → 报错
FOREIGN KEY引用别表主键,保证关联不出孤儿数据引用不存在 → 报错 1452

实测:约束拦住了非法数据

UNIQUE 撞车(想再插一个已存在的 user1@example.com):

ERROR 1062 (23000): Duplicate entry 'user1@example.com' for key 'customers.email'

外键悬空(给不存在的顾客 99999 下单):

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint
fails (`shop`.`orders`, CONSTRAINT `fk_orders_customer` FOREIGN KEY (`customer_id`)
REFERENCES `customers` (`id`))

这两条报错就是「约束在保护你」:UNIQUE 保证 email 不重复,外键保证订单一定挂在真实存在的顾客上——数据层的脏数据在写入时就被拒了。

编号意义:1062=唯一冲突、1452=外键失败、1048=NOT NULL、1064=SQL 语法错。看报错先看编号,能少查半天。

4. 约束 vs 应用层校验:都要

  • 数据库约束是最后防线(多进程同时写、绕过你代码的脚本都拦得住);
  • 应用层(表单/接口校验)负责友好提示
  • 别把业务校验全丢给 DB(报错体验差),也别裸奔只靠应用层(有并发漏洞)。

5. WHERE 的花样(查询基本功)

-- 比较 & 逻辑
WHERE age >= 18 AND city = '上海' OR status = 'vip' -- 注意 AND 优先于 OR,多条件加括号
WHERE id IN (1,2,3) -- 集合内
WHERE email LIKE 'user%' -- 前缀模糊(可走索引)
WHERE email LIKE '%user%' -- 中间模糊(走不了索引,篇 3)
WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31' -- 区间
WHERE city IS NULL -- 判空用 IS NULL,不是 = NULL!

最容易忘:判空是 IS NULL / IS NOT NULL;NULL 参与运算结果是 NULL,所以 WHERE x = NULL 永远不成立。

6. 建表「规矩清单」(给自己抄)

CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
customer_id BIGINT NOT NULL,
status VARCHAR(10) NOT NULL DEFAULT 'pending',
amount DECIMAL(10,2) NOT NULL, -- 钱用 DECIMAL,别用 float!
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_customer (customer_id), -- 外键列要有索引(InnoDB 自动给 FK 建)
CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id)
) ENGINE=InnoDB;

两个高频踩坑

  • 金额/价格用 DECIMAL(定点),用 FLOAT/DOUBLE 会有精度误差;
  • 枚举该用 VARCHAR + 应用层枚举 还是 MySQL ENUM?小范围稳定值可用 ENUM;要扩展用 VARCHAR(改 ENUM 要 DDL 锁表)。

动手

在 shop 里:插入 3 个顾客、把其中 1 个改城市、查上海顾客、删 1 个;再故意插一条重复 email 看 1062;故意插一条不存在 customer_id 的订单看 1452。

自测

  1. 四条 SQL 动词分别是什么?UPDATE/DELETE 最怕漏什么?
  2. 1062 / 1452 各代表什么被拦了?
  3. 判空为什么不能 = NULL
  4. 为什么金额用 DECIMAL 不用 DOUBLE?
  5. AUTO_INCREMENT 要配合什么一起用?

下一篇:查询进阶:JOIN / 聚合 / 子查询