本页面介绍了如何在可重复读隔离级别中使用 FOR UPDATE
子句。
对于可重复读和可序列化隔离,FOR UPDATE
子句的锁定机制有所不同。与可序列化隔离不同,FOR UPDATE
子句在可重复读隔离中不会获取锁定。如需详细了解 FOR UPDATE
中的锁定,请参阅在可序列化隔离中使用 SELECT FOR UPDATE。
如需了解如何使用 FOR UPDATE
子句,请参阅 GoogleSQL 和 PostgreSQL
FOR UPDATE
参考指南。
为何使用 FOR UPDATE
子句
当事务以可重复读隔离级别运行时,SELECT
语句查询的数据始终以事务的已建立快照时间戳返回。如果事务随后根据查询的数据进行更新,那么如果并发事务也更新了查询的数据,则可能会出现正确性问题。如需了解详情,请参阅读写冲突和正确性。
为确保 SELECT
语句查询的数据在事务提交时仍然有效,您可以将 FOR UPDATE
子句与可重复读隔离级别搭配使用。使用 FOR UPDATE
可保证事务的正确性,即使在读写冲突的情况下,数据可能在读取和修改之间被另一个事务修改。
查询语法
本部分介绍使用 FOR UPDATE
子句时的查询语法。
最常见的用法是在顶级 SELECT
语句中。例如:
SELECT SingerId, SingerInfo
FROM Singers WHERE SingerID = 5
FOR UPDATE;
FOR UPDATE
子句可确保 SELECT
语句和 SingerID = 5
查询的数据在事务提交时仍然有效,从而防止因并发事务更新查询的数据而可能出现的正确性问题。
在 WITH 语句中使用
当您在 WITH
语句的外层查询中指定 FOR UPDATE
时,FOR UPDATE
子句不会验证 WITH
语句中扫描的范围。
在以下查询中,由于 FOR UPDATE
未传播到通用表表达式 (CTE) 查询,因此未验证任何扫描范围。
WITH s AS (SELECT SingerId, SingerInfo FROM Singers WHERE SingerID > 5)
SELECT * FROM s
FOR UPDATE;
如果在 CTE 查询中指定了 FOR UPDATE
子句,则会验证 CTE 查询的扫描范围。
在以下示例中,系统会验证 SingerId > 5
所在行的 SingerId
和 SingerInfo
单元格。
WITH s AS
(SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5 FOR UPDATE)
SELECT * FROM s;
在子查询中使用
您可以在包含一个或多个子查询的外部级查询中使用 FOR UPDATE
子句。系统会验证顶级查询和子查询中扫描的范围,但表达式子查询除外。
以下查询会针对 SingerId > 5.
的行验证 SingerId
和 SingerInfo
单元格
(SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5) AS t
FOR UPDATE;
以下查询不会验证 Albums
表中的任何单元格,因为它位于表达式子查询中。系统会验证表达式子查询返回的行的 SingerId
和 SingerInfo
单元格。
SELECT SingerId, SingerInfo
FROM Singers
WHERE SingerId = (SELECT SingerId FROM Albums WHERE MarketingBudget > 100000)
FOR UPDATE;
用于查询视图
您可以使用 FOR UPDATE
子句查询视图,如以下示例所示:
CREATE VIEW SingerBio AS SELECT SingerId, FullName, SingerInfo FROM Singers;
SELECT * FROM SingerBio WHERE SingerId = 5 FOR UPDATE;
定义视图时,您无法使用 FOR UPDATE
子句。
不受支持的应用场景
以下 FOR UPDATE
用例不受支持:
- 作为在 Spanner 外部运行代码的互斥机制:请勿使用 Spanner 中的锁定来确保对 Spanner 外部的资源进行独占访问。Spanner 可能会中止事务,例如,如果重试事务(无论是通过应用代码明确进行,还是通过 Spanner JDBC 驱动程序等客户端代码隐式进行),则只能保证在已提交的尝试期间持有锁。
- 与
LOCK_SCANNED_RANGES
提示搭配使用时:您无法在同一查询中同时使用FOR UPDATE
子句和LOCK_SCANNED_RANGES
提示,否则 Spanner 会返回错误。如需了解详情,请参阅与LOCK_SCANNED_RANGES
提示的比较。 - 在全文搜索查询中:您无法在使用全文搜索索引的查询中使用
FOR UPDATE
子句。 - 在只读事务中:
FOR UPDATE
子句仅在读写事务中执行的查询中有效。 - 在 DDL 语句中:您无法在 DDL 语句中的查询中使用
FOR UPDATE
子句,这些语句会存储起来以供日后执行。例如,在定义视图时,您无法使用FOR UPDATE
子句。
后续步骤
- 了解如何在 GoogleSQL 和 PostgreSQL 中使用
FOR UPDATE
子句。 - 了解如何在可序列化隔离中使用 SELECT FOR UPDATE。
- 了解
LOCK_SCANNED_RANGES
提示。 - 了解 Spanner 中的锁定。