在可重複讀取隔離中,使用 SELECT FOR UPDATE

本頁說明如何在可重複讀取隔離中使用 FOR UPDATE 子句。

可重複讀取和可序列化隔離的 FOR UPDATE 子句鎖定機制不同。與可序列化隔離不同,FOR UPDATE 子句不會在可重複讀取隔離中取得鎖定。如要進一步瞭解 FOR UPDATE 中的鎖定,請參閱在可序列化隔離中,使用 SELECT FOR UPDATE

如要瞭解如何使用 FOR UPDATE 子句,請參閱 GoogleSQLPostgreSQL 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 所在資料列的 SingerIdSingerInfo 儲存格。

WITH s AS
  (SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5 FOR UPDATE)
SELECT * FROM s;

在子查詢中使用

您可以在具有一或多個子查詢的外層查詢中使用 FOR UPDATE 子句。頂層查詢和子查詢中掃描的範圍會經過驗證,但運算式子查詢除外。

下列查詢會驗證 SingerId > 5. 資料列的 SingerIdSingerInfo 儲存格,其中 SingerId > 5.

(SELECT SingerId, SingerInfo FROM Singers WHERE SingerId > 5) AS t
FOR UPDATE;

下列查詢不會驗證 Albums 資料表中的任何儲存格,因為該查詢位於運算式子查詢中。系統會驗證運算式子查詢傳回的資料列,是否包含 SingerIdSingerInfo 儲存格。

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 JDBC 驅動程式),Spanner 可能會中止交易,且系統只保證在已提交的嘗試期間持有鎖定。
  • 搭配 LOCK_SCANNED_RANGES 提示使用: 您無法在同一個查詢中同時使用 FOR UPDATE 子句和 LOCK_SCANNED_RANGES 提示,否則 Spanner 會傳回錯誤。詳情請參閱「LOCK_SCANNED_RANGES 提示的比較」。
  • 在全文搜尋查詢中:使用全文搜尋索引的查詢無法使用 FOR UPDATE 子句。
  • 在唯讀交易中:FOR UPDATE 子句僅在讀寫交易中執行的查詢中有效。
  • 在 DDL 陳述式中:您無法在 DDL 陳述式中的查詢使用 FOR UPDATE 子句,這些查詢會儲存起來供日後執行。舉例來說,定義檢視區塊時,無法使用 FOR UPDATE 子句。

後續步驟