外键约束仅校验单条语句的引用完整性,不保证事务一致性;其检查发生在语句执行时,依赖显式声明的ON DELETE/UPDATE行为,且要求外键列必须建索引以避免性能问题。
外键约束(FOREIGN KEY)只负责在单条语句执行时校验引用完整性,比如 INSERT 或 UPDATE 时检查被引用的 id 是否存在。它不参与事务的原子性控制——即使你在一个事务里先删父记录、再删子记录,外键会立刻报错 Cannot delete or update a parent row: a foreign key constraint fails,但这不是事务在“保证一致性”,而是约束在“阻止不一致操作”。
真正靠事务来兜底的是 ROLLBACK 机制:只要你在事务中执行多步操作,其中任意一步因外键失败或其它原因中断,整个事务可回滚。
MySQL 默认不会自动级联删除或更新,哪怕加了外键,也要明确写 ON DELETE CASCADE 或 ON DELETE SET NULL 等子句,否则默认是 RESTRICT(即拒绝操作)。
ON DELETE CASCADE:删父表行时自动删所有子表关联行 —— 快但危险,容易误删ON DELETE SET NULL:要求对应列为 NULLABLE,否则建表失败ON DELETE RESTRICT:隐式默认值,不写也会生效,但建议显式写出,避免误解SET DEFAULT 在 InnoDB 中不支持,会静默转为 RESTRICT
外键约束检查发生在语句执行阶段(statement-level),而不是事务提交时。无论你用 READ COMMITTED 还是 REPEATABLE READ,只要语句执行时被引用行不可见(比如被另一个未提交事务锁住或已删除),就会立即报错,不会等到 COMMIT 才检查。
这意味着:
Cannot add or update a child row
加了外键后,MySQL(InnoDB)会在相关操作中自动加锁,范围比你直觉中更大:
sh
ared lock(S 锁),防止父行被删/改next-key lock,可能阻塞并发插入INDEX),否则 DML 性能断崖下跌ALTER TABLE orders ADD INDEX idx_customer_id (customer_id);外键不是银弹。它把一部分数据逻辑推给了存储引擎,省了应用层判断,但也带来了锁行为不可控、迁移困难、分库分表难适配等问题。真要强一致性,得靠事务 + 应用层重试 + 补偿逻辑,而不是指望外键自己扛住所有边界。