資料庫交易提供一個安全且可預測的程式設計模型,以應對資料同時發生的變更。 傳統關聯式資料庫,如 SQL Server,允許你使用儲存程序和觸發器撰寫商業邏輯,然後直接傳送到伺服器,在資料庫引擎中執行。
傳統關聯式資料庫需要處理兩種不同的程式語言:一種非交易型應用程式語言,如 JavaScript、Python、C# 或 Java;以及由資料庫原生執行的交易程式語言,如 T-SQL。
Azure Cosmos DB 中的資料庫引擎支援完整的 ACID(原子性、一致性、隔離、耐久性)合規交易,並具備快照隔離功能。 容器 邏輯分割 範圍內的所有資料庫操作,都是在由分割區副本所託管的資料庫引擎中以交易方式執行。 這些操作包括寫入(更新邏輯分割區內一個或多個項目)與讀取操作。
下表列出不同的操作與交易類型:
| 運算 | 操作類型 | 單項或多項交易 |
|---|---|---|
| 插入(無前後觸發) | 書寫 | 單一項目交易 |
| 插入(帶有前後觸發) | 寫入與讀取 | 多項目交易 |
| 替換(無需事前/事後觸發) | 書寫 | 單一項目交易 |
| 取代 (含前置/後置觸發程序) | 寫入與讀取 | 多項目交易 |
| Upsert(無前/後觸發器) | 書寫 | 單一項目交易 |
| Upsert(帶有前後觸發器) | 寫入與讀取 | 多項目交易 |
| 刪除 (不含前置/後置觸發程序) | 書寫 | 單一項目交易 |
| 刪除(具有刪除前/後觸發器) | 寫入與讀取 | 多項目交易 |
| 執行預存程序 | 寫入與讀取 | 多項目交易 |
| 系統啟動合併程序執行 | 書寫 | 多項目交易 |
| 系統會根據項目的到期日(TTL)啟動刪除項目的執行 | 書寫 | 多項目交易 |
| 參閱 | 參閱 | 單項交易 |
| 變更摘要 | 參閱 | 多項目交易 |
| 分頁閱讀 | 參閱 | 多項目交易 |
| 分頁查詢 | 參閱 | 多項目交易 |
| 將 UDF 作為分頁查詢的一部分執行 | 參閱 | 多項目交易 |
多項目交易
Azure Cosmos DB 允許你撰寫 儲存程序、觸發器、使用者定義函式 ,並用 JavaScript 合併程序。 Azure Cosmos DB 原生支援其資料庫引擎內的 JavaScript 執行。 你可以註冊儲存程序、前後觸發器、使用者定義函式(UDF),以及在容器上合併程序,之後在 Azure Cosmos DB 資料庫引擎中以交易方式執行。 以 JavaScript 撰寫應用程式邏輯,允許在資料庫交易中直接以 JavaScript 語言自然表達控制流程、變數範圍設定、指派及整合例外處理原語。
以 JavaScript 為基礎的預存程序、觸發程序、UDF 與合併程序,會包裝在跨越邏輯分割區內所有項目的周邊 ACID 交易中,並採用快照隔離。 在執行期間,如果 JavaScript 程式擲回例外狀況,整個交易會中止並復原。 最終產生的程式設計模型簡單卻強大。 JavaScript 開發者在使用熟悉的語言結構與函式庫原語的同時,獲得一個持久的程式設計模型。
能直接在資料庫引擎內執行 JavaScript,可針對容器項目提供高效能與交易式執行的資料庫作業。 此外,由於 Azure Cosmos DB 資料庫引擎原生支援 JSON 和 JavaScript,應用程式的型別系統與資料庫之間不會有阻抗不匹配。
樂觀並行控制
樂觀並發控制(OCC) 允許你防止更新遺失和刪除。 並行且衝突的作業會受到擁有該項目的邏輯分割區所託管之資料庫引擎的一般悲觀鎖定影響。 當兩個並行操作嘗試更新邏輯分割區內項目的最新版本時,其中一個成功,另一個失敗。 如果有一或兩個操作嘗試同步更新同一項目,而先前讀取了該項目的舊值,資料庫無法確定這些操作中任一或兩個先前讀取的值是否確實是該項目的最新值。
幸好,這種情況可以在讓兩個作業進入資料庫引擎內的交易界限之前,由 OCC 偵測到。 OCC 會保護您的資料,避免意外覆寫其他人所做的變更。 同時也能防止他人不小心覆寫你的修改。
實作使用 ETag 與 HTTP 標頭的樂觀並發控制
每個儲存在 Azure Cosmos DB 容器中的項目都有系統定義 _etag 的屬性。 每次項目更新時,伺服器會自動產生並更新 的 _etag 值。
_etag 可搭配客戶端提供的 if-match 請求標頭使用,讓伺服器決定項目是否能被條件更新。 如果標頭的 if-match 值與伺服器的 _etag 值相符,該項目就會被更新。 如果請求標頭的值 if-match 不再是當前,伺服器會以「HTTP 412 前置條件失敗」回應訊息拒絕該操作。 接著,用戶端可以重新提取項目以取得伺服器上項目的目前版本,或使用自己的 _etag 值覆寫伺服器上的項目版本。 此外,_etag 可以與 if-none-match 標頭一起使用,以判斷是否需要重新擷取資源。
每次更新時,該項目的 _etag 價值都會改變。 對於替換項目操作,必須將 if-match 明確表示為請求選項的一部分。 舉例來說,可以參考 GitHub 上的範例程式碼。 預存程序所觸及的所有已寫入項目,其 _etag 值都會隱含檢查。 若偵測到任何衝突,預存程序會復原交易並擲回例外狀況。 使用此方法,預存程序內的寫入要嘛全部以不可分割方式套用,要嘛完全不套用。 這是給應用程式重新套用更新並重試原始客戶端請求的訊號。
樂觀並行控制與全域分布
項目的並行更新會受到 Azure Cosmos DB 通訊協定層的 OCC 影響。 對於設定為 單一區域寫入的 Azure Cosmos DB 帳號,Azure Cosmos DB 會確保你更新(或刪除)的項目的客戶端版本與 Azure Cosmos DB 容器中的項目版本相同。 這確保你的寫作不會被他人的文字意外覆蓋,反之亦然。 在多使用者環境中,樂觀並發控制能防止你不小心刪除或更新錯誤的項目版本。 因此,項目能避免臭名昭著的「遺失更新」或「遺失刪除」問題。
在具備多區域寫入支援的 Azure Cosmos DB 帳號中,若該資料與本地區域的資料相符,則可獨立提交到其他次要區域。 一旦新資料在次要區域本地提交,就會合併到樞紐或主要區域。 如果衝突解決策略將新資料合併到樞紐區域,那麼這些資料會與新的 _etag 一同在全球範圍內複製。 如果衝突解決原則拒絕新資料,次要區域會復原為原始資料與 _etag。
後續步驟
了解更多關於資料庫交易與樂觀並發控制的資訊: