如果我在 oracle 中运行一条更新语句,因为它与 where 子句不匹配并且我没有提交,所以它显示“更新了 0 行”,它是否仍会锁定表的任何部分?我的猜测是否定的,但我无法证明。
3 回答
在没有更新任何内容的更新之后不会持有行锁(毕竟,如果没有行,应该锁定哪一个?)
您的事务仍将有一些共享锁(在表上),但这些锁只是为了防止其他事务更改表。它基本上与 select 语句在表上获得的“锁定”类型相同。
从手册:
仅当写入者修改时才会锁定行。
行锁,也称为 TX 锁,是对单行表的锁。事务为修改的每一行获取一个行锁
因此,如果没有更改任何行,就不可能有锁。
它不持有任何锁。
简单的测试用例
- 打开两个 oracle 会话(sqlplus 或 sqldeveloper 或通过任何其他方式)
- 更新 table1 where 子句(会话 1)
- 更新 table1 where 子句(会话 2)
- 从 session1 提交(如果有表锁,那么这应该挂起)
- 从 session2 提交(如果有表锁,则此语句将导致死锁)
条件与行锁定相同(如果存在,两个会话都删除同一行)。
据记载:
INSERT、UPDATE、DELETE 和 SELECT ... FOR UPDATE 语句的锁定特性如下:
包含 DML 语句的事务在该语句修改的行上获取排他行锁。在锁定事务提交或回滚之前,其他事务无法更新或删除锁定的行。
包含 DML 语句的事务不需要在子查询或隐式查询(例如 WHERE 子句中的查询)选择的任何行上获取行锁。DML 语句中的子查询或隐式查询保证在查询开始时是一致的,并且看不到它所属的 DML 语句的效果。
事务中的查询可以看到同一个事务中之前的 DML 语句所做的更改,但看不到在它自己的事务之后开始的其他事务的更改。
除了必要的排他行锁之外,包含 DML 语句的事务至少会在包含受影响行的表上获取一个行排他表锁。如果包含事务已持有该表的共享、共享行独占或独占表锁,则不会获取行独占表锁。如果包含事务已经持有行共享表锁,Oracle 数据库会自动将此锁转换为行独占表锁。
表锁对于在更新过程中保护表免受更改是必要的,如果更新没有修改任何行,那么这是唯一应用的锁。
如果语句对一行执行更新,导致该行没有更改(例如,对于 date_of_birth 已经为空的行,SET DATE_OF_BIRTH = NULL,则仍会使用行锁。