修改数据与事务 · SQL 与数据库
怎么安全地修改数据?
课程目录为什么需要它
读数据很安全,写数据才会闯大祸。不带 WHERE 的 UPDATE 会改掉每一行,而且没有撤销键。事务让多个修改要么一起成功、要么一起失败,银行转账就是靠它才不会转到一半丢了钱。
直觉理解
INSERT INTO t (cols) VALUES (...)添加行。UPDATE t SET col = value WHERE ...修改行。DELETE FROM t WHERE ...删除行。
好习惯:先写 SELECT … WHERE …,确认它返回的正好是你想改的行,再把它改成 UPDATE 或 DELETE,用同一个 WHERE。
BEGIN; … COMMIT; 把修改包进一个事务。COMMIT 之前出了任何问题,ROLLBACK 都能全部恢复原样。
定义
事务 Transaction
A group of statements that is applied all together or not at all. It starts with BEGIN and ends with COMMIT (keep) or ROLLBACK (throw away).一组语句,要么全部生效,要么全不生效。以 BEGIN 开始,以 COMMIT(保留)或 ROLLBACK(丢弃)结束。
约束 Constraint
A rule the database enforces, such as NOT NULL or PRIMARY KEY. A statement that breaks it fails with an error instead of storing bad data.数据库强制执行的规则,比如 NOT NULL 或 PRIMARY KEY。违反规则的语句会报错,而不是存进坏数据。
示例
插入、修改、检查
在互动课里运行加一个顾客,改一个城市,再看结果。
INSERT INTO customers (id, name, city) VALUES (6, 'Fei', 'Chengdu');
UPDATE customers SET city = 'Paris' WHERE name = 'Dana';
SELECT name, city FROM customers WHERE id >= 4;输出
name | city Dana | Paris Eli | NULL Fei | Chengdu
逐步执行
- L1多了第六行。
- L2只有符合 WHERE 的行会变:只有 Dana。
- L3检查一下结果。
Dana | Paris
用事务做一次转移
在互动课里运行在两个货架之间挪库存:两处修改要么都做,要么都不做。这里我们回滚了,所以什么都没变。
CREATE TABLE stock (shelf TEXT PRIMARY KEY, units INTEGER);
INSERT INTO stock VALUES ('A', 10), ('B', 0);
BEGIN;
UPDATE stock SET units = units - 4 WHERE shelf = 'A';
UPDATE stock SET units = units + 4 WHERE shelf = 'B';
ROLLBACK;
SELECT * FROM stock;输出
shelf | units A | 10 B | 0
逐步执行
- L3从这里开始,修改都是暂时的。
- L6两次修改都丢掉。
- L7还是 A 10、B 0。如果换成 COMMIT,就是 6 和 4。
A | 10
常见错误
UPDATE 不带 WHERE
UPDATE products SET price = 0; 会让所有东西都免费。一定先用同样的 WHERE 跑一遍 SELECT。
用用户输入拼 SQL
绝不要把用户输入的文字直接拼进语句。在程序里用 ? 占位符;网络安全课会告诉你不这样做会出什么事。
小测验
1. 这段代码会输出什么?
UPDATE products SET price = price * 2 WHERE category = 'paper';
SELECT SUM(price) AS total FROM products;查看答案
答案:B
纸品原来是 3.5 + 1.5 = 5.0,变成 10.0。其余是 49.0,所以总和是 59.0。
2. 转账执行了 `UPDATE … - 4`,然后第二个 UPDATE 之前服务器崩了。两条语句都包在 BEGIN … COMMIT 里,最后存下的是什么?
查看答案
答案:B
没有 COMMIT,事务没完成,数据库重启时会丢弃它。
动手练习
3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。
- 预测输出删除之后数一数
准确写出这段代码的结果。
- 改需求给一类商品打折
这条 UPDATE 会给所有商品降价。改成只对
home类商品生效,最后的 SELECT 保持不变。 - 从零写记录一笔新订单
Eli(顾客 5)在
2025-03-08买了 3 个 Mug(商品 5)。在一个事务里(BEGIN; … COMMIT;)把它记为第 8 号订单,然后查出 Eli 所有订单的qty。
本课术语
| 术语 | 中文 | 英文定义 |
|---|---|---|
| Transaction | 事务 | Statements that take effect all together or not at all. |
| Rollback | 回滚 | Undoing every change made since BEGIN. |
| Constraint | 约束 | A rule the database enforces on stored data. |