7、UPDATE与DELETE操作:更新记录、删除记录、事务保护下的修改、级联操作
好,咱们今天聊聊数据库里最“危险”的两个操作——UPDATE和DELETE。说它们危险,是因为一旦执行错了,数据就没了,或者变得乱七八糟。我刚开始做嵌入式数据库开发那会儿,就吃过这个亏。有一次在产线上跑批量更新,少写了一个WHERE条件,结果整张表的价格字段全变成了同一个数……嗯,从那以后,我写UPDATE和DELETE之前,都会先看一眼WHERE子句,确认三遍。
7.1 更新记录:UPDATE 语句的细节
UPDATE说白了就是改数据。语法很简单,但坑不少。
UPDATE 表名 SET 列1 = 值1, 列2 = 值2 WHERE 条件;
我个人习惯,写UPDATE之前,先用SELECT把要改的行查出来看一眼。比如:
-- 先查
SELECT * FROM products WHERE product_id = 101;
-- 确认无误后再改
UPDATE products SET price = 29.99 WHERE product_id = 101;
你想想看,如果直接写UPDATE,万一条件写错了,连后悔药都没得吃。在SQLite里,UPDATE默认是不支持回滚的——除非你开了事务。这个咱们后面细说。
7.2 删除记录:DELETE 与 TRUNCATE 的区别
DELETE和TRUNCATE都能删数据,但本质完全不同。
| 操作 | 特点 | 能否回滚 | 速度 |
|---|---|---|---|
| DELETE | 逐行删除,触发触发器 | 事务内可回滚 | 慢(记录日志) |
| TRUNCATE | 直接释放数据页,不逐行删 | 通常不可回滚 | 极快 |
我在项目中遇到过一个问题:用DELETE删了10万条记录,结果因为没开事务,删到一半断电了,数据处于半删不删的状态,恢复起来特别麻烦。后来我学乖了,批量删除一定包在事务里。
BEGIN TRANSACTION;
DELETE FROM logs WHERE timestamp < '2023-01-01';
-- 检查影响行数
SELECT changes();
-- 如果影响行数不对,就 ROLLBACK
ROLLBACK; -- 或者 COMMIT;
7.3 事务保护下的修改:原子性才是王道
事务这东西,说白了就是“要么全做,要么全不做”。我经常跟团队里的新人说:任何涉及多条记录的修改,都必须包在事务里。
举个例子,你要把A账户扣100块,B账户加100块。这两条UPDATE必须在一个事务里:
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 假设这里检查一下余额是否足够
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 如果一切正常
COMMIT;
-- 如果中间出错了
-- ROLLBACK;
为什么会这样?因为如果第一条UPDATE成功了,第二条失败了,钱就凭空消失了。事务就是用来防止这种“半截子操作”的。
7.4 级联操作:外键约束下的自动更新与删除
级联操作,就是当你改了主表的记录,从表自动跟着变。比如你删了一个客户,他所有的订单也应该被删掉——这就是级联删除。
定义外键时加上 ON DELETE CASCADE 或 ON UPDATE CASCADE:
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER,
amount REAL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
这样,当你执行:
DELETE FROM customers WHERE customer_id = 5;
所有 customer_id = 5 的订单也会被自动删除。听起来很方便对吧?但我要提醒你:级联操作一定要谨慎使用。我曾经见过一个项目,因为级联删除设计得太“激进”,删一个用户结果连带删了上千条关联记录,最后数据恢复花了两天。
7.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作一个“操作决策流程图”:
这张图的核心逻辑是:先判断影响范围,再决定是否用事务,最后考虑外键级联。每一步都走对了,数据安全就有保障。
7.6 实战建议总结
- 写UPDATE/DELETE前,先SELECT确认——这是成本最低的防错手段。
- 批量操作必须包事务——哪怕只是删10条记录,也养成习惯。
- 级联操作要克制——能用代码逻辑处理的,尽量别依赖数据库级联。
- SQLite记得开外键——PRAGMA foreign_keys = ON; 这句话写进初始化代码里。
嗯,关于UPDATE和DELETE,今天就聊这么多。这些操作看起来简单,但实际项目中出问题最多的就是它们。记住一句话:数据修改前多花一分钟确认,可能省下后面一整天恢复数据的时间。