← 返回题目列表

Oracle 事务锁有哪些?行锁、表锁和死锁怎么理解?

高频 中等 第 8 / 32 题 更新于 2026/07/28
Oracle事务死锁并发控制

简化版

Oracle 的普通 DML 会自动加锁,常见是行级锁和表级锁。更新一行时会锁住对应行,其他事务修改同一行要等待;普通一致性读通常不被行锁阻塞。死锁是多个事务互相等待对方持有的资源,Oracle 会检测死锁并回滚其中一条语句,应用需要处理异常并优化加锁顺序。

详细版

Oracle 锁常见考点:

  • SELECT 普通查询走一致性读,通常不阻塞 DML;
  • SELECT ... FOR UPDATE 会对查询到的行加锁;
  • INSERTUPDATEDELETE 会自动加行锁;
  • DML 还会持有表级锁,用来保护表结构不被不兼容 DDL 修改;
  • 死锁通常来自多个事务访问资源顺序不一致;
  • 长事务会持锁更久,放大锁等待。

行锁保护的是具体数据行,表锁更多用于协调表级操作。面试时要把“锁的粒度”和“读一致性”一起讲清楚,不能简单说 Oracle 读写永远互不影响。

完整版教学

一、Oracle 为什么还需要锁

Oracle 有读一致性,普通查询可以通过 UNDO 看到历史版本,所以读写冲突少。但写写冲突仍然必须控制。

如果两个事务同时更新同一行账户余额:

UPDATE account SET balance = balance - 100 WHERE id = 1;

数据库必须让其中一个事务等待,否则最终余额会变得不可预测。这就是行锁存在的意义。

二、行锁保护具体行

Oracle 执行 UPDATEDELETE 时,会锁住被修改的行。锁会一直持有到事务提交或回滚。

例如事务 A:

UPDATE users SET name = 'Tom' WHERE id = 1;

事务 B 如果也更新 id = 1,就会等待 A 提交或回滚。但 B 普通查询这行时,通常可以通过一致性读看到合适版本。

三、表级锁不是一定锁整张表不能读写

Oracle DML 也会持有表级锁,但它主要用于保护表结构,防止执行 DML 时表被某些不兼容 DDL 改掉。

这和“把整张表的数据行都锁住”不是一回事。面试里说表锁时要具体说明锁模式和目的,避免把表级锁理解成所有人都不能访问表。

如果手动执行:

LOCK TABLE orders IN EXCLUSIVE MODE;

那就会产生更强的表级锁,业务系统里要非常谨慎。

四、SELECT FOR UPDATE 是显式加锁读

普通 SELECT 是一致性读,不会锁住数据行。但:

SELECT * FROM orders WHERE id = 100 FOR UPDATE;

会锁住返回的行,常用于抢单、任务领取、先查后改等场景。

使用时要注意:

  • 条件要尽量走索引,避免锁范围失控;
  • 事务要尽快结束;
  • 可以使用 NOWAITSKIP LOCKED 控制等待行为;
  • 不要在持锁事务里做耗时远程调用。

五、死锁通常来自访问顺序不一致

典型死锁:

事务 A:先更新订单 1,再更新订单 2
事务 B:先更新订单 2,再更新订单 1

A 等 B 释放订单 2,B 等 A 释放订单 1,双方互相等待。Oracle 会检测死锁,并让其中一个语句失败。

工程上的解决方法:

  • 批量更新统一按主键顺序;
  • 缩短事务时间;
  • 减少跨多个资源的事务范围;
  • 对热点资源使用更明确的队列或串行化策略;
  • 捕获死锁异常并让业务安全重试。

六、常见误区与追问

场景锁行为风险
普通 SELECT一致性读,不锁行看到的是快照版本
UPDATE/DELETE锁住被修改行同行写写等待
SELECT FOR UPDATE显式锁返回行事务过长会阻塞别人

易错点:Oracle “读写不互相阻塞”说的是普通一致性读和 DML 的常见关系,不代表所有读都不加锁,也不代表写写不会等待。

典型死锁时间线:

T1: 事务 A 锁住 order_id=1
T2: 事务 B 锁住 order_id=2
T3: 事务 A 请求 order_id=2,等待 B
T4: 事务 B 请求 order_id=1,等待 A
T5: Oracle 检测死锁,回滚其中一个语句

如果批量任务统一按主键升序更新,就能避免很多“你先 1 后 2、我先 2 后 1”的互相等待。

  • 误区:Oracle 有一致性读,所以不需要锁。 普通读少阻塞写,但写写冲突仍必须用行锁控制。
  • 误区:表级锁等于整张表不能查询。 DML 的表级锁主要协调结构变更,不等于锁住所有数据行。
  • 误区:死锁只能靠数据库自动处理。 数据库能检测并打断一个语句,但应用要处理异常,并从访问顺序和事务范围上预防。
  • 追问:SELECT FOR UPDATE 适合什么场景? 适合先锁定再处理的任务领取、抢单、库存校验等,但事务要短。
  • 追问:NOWAITSKIP LOCKED 有什么价值? NOWAIT 避免长时间等待,SKIP LOCKED 可跳过已锁行,常用于并发任务领取。
  • 追问:如何降低死锁概率? 统一资源访问顺序、缩短事务、避免持锁做远程调用、减少热点行、必要时使用队列串行化。

七、加强记忆

Oracle 锁要记住:普通读靠一致性读,写写冲突靠行锁,DML 还会有表级协调锁,FOR UPDATE 是主动加锁读。死锁不是神秘问题,多数来自多个事务访问资源顺序不一致;统一顺序、缩短事务、减少热点竞争是核心解法。