

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Lock:transactionid
<a name="wait-event.locktransactionid"></a>

`Lock:transactionid` 事件表示交易正在等待資料列層級鎖定。

**Topics**
+ [支援的引擎版本](#wait-event.locktransactionid.context.supported)
+ [Context](#wait-event.locktransactionid.context)
+ [等待變多的可能原因](#wait-event.locktransactionid.causes)
+ [動作](#wait-event.locktransactionid.actions)

## 支援的引擎版本
<a name="wait-event.locktransactionid.context.supported"></a>

所有 RDS for PostgreSQL 版本都支援此等待事件資訊。

## Context
<a name="wait-event.locktransactionid.context"></a>

`Lock:transactionid` 事件表示交易嘗試取得的資料列層級鎖定已授予同一時間執行的另一個交易。因為此鎖定，已封鎖出現 `Lock:transactionid` 等待事件的工作階段。當引起封鎖的交易在 `COMMIT` 或 `ROLLBACK` 陳述式中結束時，被封鎖的交易就可以繼續進行。

RDS for PostgreSQL 的多版本並行控制語意保證讀取器不會封鎖寫入器，而寫入器也不會封鎖讀取器。引起封鎖和被封鎖的交易必須發出下列類型的衝突陳述式，才會發生資料列層級衝突：
+ `UPDATE`
+ `SELECT … FOR UPDATE`
+ `SELECT … FOR KEY SHARE`

`SELECT … FOR KEY SHARE` 陳述式是特殊情況。資料庫使用 `FOR KEY SHARE` 子句來最佳化參考完整性的效能。如果資料列上有資料列層級鎖定，則會封鎖其他資料表上參考此資料列的 `INSERT`、`UPDATE` 及 `DELETE` 命令。

## 等待變多的可能原因
<a name="wait-event.locktransactionid.causes"></a>

此事件比平時更常出現時，通常是因為 `UPDATE`、`SELECT … FOR UPDATE` 或`SELECT … FOR KEY SHARE` 陳述式兼具下列情況。

**Topics**
+ [高度並行](#wait-event.locktransactionid.concurrency)
+ [交易閒置](#wait-event.locktransactionid.idle)
+ [長時間執行的交易](#wait-event.locktransactionid.long-running)

### 高度並行
<a name="wait-event.locktransactionid.concurrency"></a>

RDS for PostgreSQL 可以使用精細的資料列層級鎖定語意。有下列情況時，較可能發生資料列層級衝突：
+ 高度並行工作負載爭用相同的資料列。
+ 並行增加。

### 交易閒置
<a name="wait-event.locktransactionid.idle"></a>

有時候 `pg_stat_activity.state` 資料欄會顯示 `idle in transaction` 值。已啟動交易但尚未發出 `COMMIT` 或 `ROLLBACK` 的工作階段會出現此值。如果 `pg_stat_activity.state` 值不是 `active`，`pg_stat_activity` 中會顯示最近要完成執行的查詢。因為開啟的交易持有鎖定，引起封鎖的工作階段目前未處理查詢。

如果閒置交易已獲得資料列層級鎖定，可能會阻止其他工作階段取得鎖定。這種情況導致頻繁發生等待事件 `Lock:transactionid`。若要診斷問題，請檢查 `pg_stat_activity` 和 `pg_locks` 的輸出。

### 長時間執行的交易
<a name="wait-event.locktransactionid.long-running"></a>

長時間執行的交易會長時間持有鎖定。這些長期持有的鎖定可能阻止其他交易執行。

## 動作
<a name="wait-event.locktransactionid.actions"></a>

資料列鎖定會造成 `UPDATE`、`SELECT … FOR UPDATE` 或 `SELECT … FOR KEY SHARE` 陳述式之間發生衝突。嘗試解決之前，請查明這些陳述式是否在同一個資料列上執行。使用此資訊來選擇以下各節描述的策略。

**Topics**
+ [因應高度並行](#wait-event.locktransactionid.actions.problem)
+ [因應閒置的交易](#wait-event.locktransactionid.actions.find-blocker)
+ [因應長時間執行的交易](#wait-event.locktransactionid.actions.concurrency)

### 因應高度並行
<a name="wait-event.locktransactionid.actions.problem"></a>

如果問題在於並行，請嘗試下列其中一項技巧：
+ 降低應用程式中的並行。例如，減少作用中工作階段的數目。
+ 實作連線集區。若要了解如何使用 RDS Proxy 來建立連線集區，請參閱 [Amazon RDS Proxy ](rds-proxy.md)。
+ 將應用程式或資料模型設計成避免爭用 `UPDATE` 和 `SELECT … FOR UPDATE` 陳述式。您也可以減少 `SELECT … FOR KEY SHARE` 陳述式存取的外部索引鍵數目。

### 因應閒置的交易
<a name="wait-event.locktransactionid.actions.find-blocker"></a>

如果 `pg_stat_activity.state` 顯示 `idle in transaction`，請使用下列策略：
+ 盡可能開啟自動遞交。這種方法可以防止交易在等待 `COMMIT` 或 `ROLLBACK` 時封鎖其他交易。
+ 搜尋缺少 `COMMIT`、`ROLLBACK` 或 `END` 的程式碼路徑。
+ 確保應用程式中的異常處理邏輯一定有路徑通往有效 `end of transaction`。
+ 確保應用程式以 `COMMIT` 或 `ROLLBACK` 結束交易後處理查詢結果。

### 因應長時間執行的交易
<a name="wait-event.locktransactionid.actions.concurrency"></a>

如果長時間執行的交易導致頻繁出現 `Lock:transactionid`，請嘗試下列策略：
+ 避免長時間執行的交易使用資料列鎖定。
+ 盡可能實作自動遞交來限制查詢的長度。