簡介
交易是在資料庫中處理的邏輯群組,它封裝一個或多個跨多個文件的操作,例如讀取和/或寫入。資料庫不是在個別語句中執行,而是能夠將操作群組解釋為一個有凝聚力的單元並對其採取行動。這有助於確保資料集在許多密切相關的語句過程中的一致性。
在本指南中,我們將首先討論什麼是交易、何時在文件模型中使用交易,以及它們在 MongoDB 中的概念性運作方式。
如果您正在使用 MongoDB,請查看 Prisma 的 MongoDB 連接器!您可以使用 Prisma Client 來自信地管理生產環境的 MongoDB 資料庫。
要開始使用 MongoDB 和 Prisma,請查看我們的從頭開始入門指南,或如何新增至現有專案。
什麼是交易?
交易是一種將多個語句分組和隔離在一起,以便作為單一操作處理的方式。在交易中,命令不是個別執行,而是將命令捆綁在一起,並在與其他請求不同的上下文中執行。
隔離性是交易的重要組成部分。在交易內部,執行的語句只能影響交易本身的環境。從交易內部來看,語句可以修改資料,並且結果會立即可見。從外部來看,在交易提交之前不會進行任何變更,屆時交易內的所有操作將一次全部可見。
這些功能透過提供原子性和隔離性,協助資料庫實現 ACID 合規性。這些共同協助資料庫維持一致性。此外,交易中的變更在提交到非揮發性儲存裝置之前,不會傳回為成功,這提供了持久性。
MongoDB 支援多文件 ACID 交易和分散式多文件 ACID 交易。本質上,文件模型允許將相關資料儲存在單一文件中。文件模型與原子文件更新相結合,在大多數使用案例中消除了對交易的需求。但是,在某些情況下,多文件、多集合 MongoDB 交易是您的最佳選擇。
何時在文件模型中使用交易
文件模型本身就解決了交易針對的許多需求。儘管如此,在文件模型中,有些使用案例仍然因為需要利用交易而脫穎而出。
需要交易的應用程式通常是那些在不同方之間交換價值的應用程式。一些範例包括「系統記錄」或「業務線」應用程式。
多文件交易的優點專為在系統中轉移資金而量身定制,例如銀行應用程式或支付處理、供應鏈或貨運系統(其中貨物所有權轉移)或電子商務。這些範例通常將跨多個流程的變更包裝在一起,並且需要與交易提供的全有或全無方法保持強烈一致性。
如何使用交易?
MongoDB 提供兩個 API 來使用交易。第一個是核心 API,其語法與關聯式資料庫類似。第二個回呼 API 是在 MongoDB 中使用交易的建議方法。
兩種 API 的比較最好總結在下表中
核心 API | 回呼 API |
---|---|
需要顯式呼叫以啟動和提交交易 | 啟動交易、執行指定的操作,並提交(或在錯誤時中止) |
不會自動合併 TransientTransactionError 和 UnknownTransactionCommitResult 的錯誤處理邏輯,而是授予整合自訂錯誤處理的能力。 | 自動合併 TransientTransactionError 和 UnknownTransactionCommmitResult 的錯誤處理邏輯。 |
需要將顯式邏輯會話傳遞到 API 以進行特定交易。 | 需要將顯式邏輯會話傳遞到 API 以進行特定交易。 |
如果您希望開始使用 MongoDB 和 Prisma,請查看我們的從頭開始入門指南,或如何新增至現有專案。
建立交易會話
交易通常是透過 API 方法從外部應用程式編寫和執行的,並使用應用程式語言的適當 MongoDB 驅動程式。
為了示範,我們將逐步說明如何透過 MongoDB Shell 建立交易。我們將使用範例資料庫和集合,以協助概念化交易在實務中的運作方式。
注意:如果交易會話在初始 startTransaction()
方法之後執行超過 60 秒,MongoDB 將自動中止操作。發生這種情況的原因是交易通常在自動運作的應用程式中進行,而不是由人員在 Shell 中發出命令。以下步驟旨在概念化從開始到結束的交易會話。
首先,我們有一個名為 literature
的簡單資料庫,其中有一個名為 authors
的集合。執行快速 find()
查詢,我們可以查看文件結構,其中包含作者姓名和他們的作品標題。
db.authors.find()
[{_id: ObjectId("620397dd4b871fc65c193106"),first_name: 'James',last_name: 'Joyce',title: 'Ulysses'},{_id: ObjectId("620398016ed0bb9e23785973"),first_name: 'William',last_name: 'Gibson',title: 'Neuromancer'},{_id: ObjectId("6203981d6ed0bb9e23785974"),first_name: 'George',last_name: 'Orwell',title: 'Homage to Catalonia'},{_id: ObjectId("620398516ed0bb9e23785975"),first_name: 'James',last_name: 'Baldwin',title: 'The Fire Next Time'}]
現在我們有了資料庫,我們可以展示直接在 MongoDB Shell 中使用交易的步驟。我們還將示範在一個會話中進行的交易可能無法被外部來源偵測到。
首先,我們需要建立一個會話,就像您在使用 API 時一樣。
var session = db.getMongo().startSession()
這個新建立的 session
變數將儲存會話物件。
下一步是透過呼叫 startTransaction()
方法來啟動交易
session.startTransaction({ "readConcern": { "level": "snapshot" },"writeConcern": { "w": "majority }})
startTransaction()
方法有兩個選項:readConcern
和 writeConcern
。您可以在 MongoDB 文件中閱讀有關這些選項的更多詳細資訊。我們將 readConcern
level
設定為 snapshot
,如果交易使用 writeConcern
「majority」 提交,則從大多數已提交資料的快照傳回資料。
當您使用 w: "majority"
寫入考量以及 "snapshot"
的讀取考量層級提交時,這保證了操作具有大多數已提交資料的同步快照。如果沒有特定要求,這種寫入和讀取考量的配置可以被認為是良好的預設值。
如果成功,該方法將不會傳回任何內容,如果發生任何錯誤,則需要中止交易,這將在稍後討論。
在交易會話內工作
現在您已啟動交易會話,您必須在前一節的 session
變數的上下文中執行語句。
在會話中將您的集合表示為變數,以簡化語法會很有幫助。您可以按如下方式執行此操作
var authors = session.getDatabase('literature').getCollection('authors')
這個新建立的變數將像在交易會話外部的 Shell 中工作時的 db.authors
一樣工作。您可以透過開啟第二個 Shell 視窗、連線到您的叢集並執行 db.authors.find()
來驗證這一點。兩個語句都將傳回相同的文件。
在會話內部,我們現在想要模擬外部應用程式可能執行的操作,並向資料庫新增記錄。我們可以透過以下方式將其新增到我們的 authors
集合中
authors.insertOne( {"first_name": "Virginie","last_name": "Despentes","title": "Vernon Subutex") })
MongoDB 將傳回成功
{acknowledged: true,insertedId: ObjectId("6203a075c374636bc6976baa")}
如果我們現在在會話中執行 authors.find()
,我們將傳回先前的結果,並包含我們的新增內容
[{_id: ObjectId("620397dd4b871fc65c193106"),first_name: 'James',last_name: 'Joyce',best_title: 'Ulysses'},{_id: ObjectId("620398016ed0bb9e23785973"),first_name: 'William',last_name: 'Gibson',best_title: 'Neuromancer'},{_id: ObjectId("6203981d6ed0bb9e23785974"),first_name: 'George',last_name: 'Orwell',best_title: 'Homage to Catalonia'},{_id: ObjectId("620398516ed0bb9e23785975"),first_name: 'James',last_name: 'Baldwin',best_title: 'The Fire Next Time'},{_id: ObjectId("6203a075c374636bc6976baa"),first_name: 'Virginie',last_name: 'Despentes',best_title: 'Vernon Subutex'}]
由於此交易會話尚未提交,我們將不會在會話外部的 MongoDB Shell 中看到它傳回相同的結果。為了確認,我們在另一個 MongoDB Shell 實例中執行 db.authors.find()
,然後我們傳回原始文件。
[{_id: ObjectId("620397dd4b871fc65c193106"),first_name: 'James',last_name: 'Joyce',best_title: 'Ulysses'},{_id: ObjectId("620398016ed0bb9e23785973"),first_name: 'William',last_name: 'Gibson',best_title: 'Neuromancer'},{_id: ObjectId("6203981d6ed0bb9e23785974"),first_name: 'George',last_name: 'Orwell',best_title: 'Homage to Catalonia'},{_id: ObjectId("620398516ed0bb9e23785975"),first_name: 'James',last_name: 'Baldwin',best_title: 'The Fire Next Time'}]
這種差異表明交易目前仍處於不明確狀態。它仍然可以成功並提交到資料庫,或者可能失敗並中止。無論哪種方式,資料庫最終都將處於一致的狀態。它將包含新記錄,或導致回滾到與交易會話開始之前相同的狀態。
我們在會話中執行 commitTransaction()
方法以提交交易,並使資料庫達到新的 consistent 狀態
session.commitTransaction()
現在,新記錄將同時存在於交易會話發生的 MongoDB Shell 和交易外部的 MongoDB Shell 實例中。
中止交易
現在我們已經從啟動會話一直到提交會話,我們可以探索交易的替代結果。
此路徑的開頭相同,僅在提交點發生變化。如果我們想要捨棄交易正在進行的變更,那麼我們可以使用 abortTransaction()
方法,如下所示在會話 Shell 中
session.abortTransaction()
此方法取消交易會話並捨棄任何潛在的變更。資料庫不會產生新的 consistent 狀態,而是回滾變更,並保持與交易會話首次啟動時相同的狀態。
結論
在本指南中,我們討論了什麼是交易,以及交易最適合 MongoDB 中的哪些使用案例。我們還概念性地逐步說明了 MongoDB Shell 中的交易會話過程,以便您可以了解外部應用程式將如何運作。
交易是關聯式資料庫的基本需求,也是文件模型資料庫(例如 MongoDB)中特定使用案例的需求。對於文件模型,一般建議是將一起存取的資料儲存在一起。但是,有時情況並非如此,因此了解交易的基礎知識非常重要。
如果您正在使用 MongoDB,請查看 Prisma 的 MongoDB 連接器!您可以使用 Prisma Client 來自信地管理生產環境的 MongoDB 資料庫。
要開始使用 MongoDB 和 Prisma,請查看我們的從頭開始入門指南,或如何新增至現有專案。
常見問題
是的,MongoDB 交易可以在 Node.js 中使用。
MongoDB 為「如何在 Node.js 中使用 MongoDB 交易」提供了有用的入門指南。
ACID 是原子性、一致性、隔離性和持久性的首字母縮寫。所有這些屬性都與保持資料庫處於有效狀態有關。
由於交易是一組一起執行的資料庫操作,因此確保在發生意外錯誤時資料庫的有效性至關重要。符合 ACID 標準的交易可防止資料庫狀態無效。
MongoDB 交易存在於會話中。您可以使用 startSession()
建立會話,然後使用 session.startTransaction()
來暫存您的交易操作以進行提交。
若要有意回滾這些變更,您可以使用 session.abortTransaction()
方法來捨棄在會話中啟動的操作。這必須在 session.commitTransaction()
方法之前進行。
使用 MongoDB 時,有幾個交易最佳實務需要考慮。您需要確保進行最佳化以將交易執行時間保持在啟動後 60 秒內,因為 MongoDB 會自動中止任何更長的時間。
交易中的操作次數不應超過交易中修改的 1,000 個文件。此外,由於多個操作在交易中發生,因此選擇適當的讀取和寫入考量非常重要。MongoDB 提供了一份詳盡的最佳實務指南,其中涵蓋了這方面的內容以及更多內容。
是的,MongoDB 在 MongoDB 4.0 及更高版本中支援多文件 ACID 交易。