如果您編寫 Web 服務,您很可能會與資料庫互動。有時,您需要進行必須以原子方式應用的更改 - 要么全部成功,要么全部失敗。這就是事務的用武之地。在本文中,我將向您展示如何在程式碼中實現事務,以避免抽象洩漏問題。
例子
一個常見的例子是處理付款:
- 您需要取得使用者的餘額並檢查是否足夠。
- 然後,您更新餘額並保存。
結構
通常,您的應用程式將有兩個模組來將業務邏輯與資料庫相關程式碼分開。
儲存庫模組
此模組處理所有與資料庫相關的操作,例如 SQL 查詢。下面,我們定義兩個函數:
- get_balance — 從資料庫中檢索使用者的餘額。
- set_balance — 更新使用者的餘額。
import { Injectable } from '@nestjs/common'; import postgres from 'postgres'; @Injectable() export class BillingRepository { constructor( private readonly db_connection: postgres.Sql, ) {} async get_balance(customer_id: string): Promise<number null> { const rows = await this.db_connection` SELECT amount FROM balances WHERE customer_id=${customer_id} `; return (rows[0]?.amount) ?? null; } async set_balance(customer_id: string, amount: number): Promise<void> { await this.db_connection` UPDATE balances SET amount=${amount} WHERE customer_id=${customer_id} `; } } </void></number>
服務模組
服務模組包含業務邏輯,例如取得餘額、驗證餘額以及保存更新後的餘額。
import { Injectable } from '@nestjs/common'; import { BillingRepository } from 'src/billing/billing.repository'; @Injectable() export class BillingService { constructor( private readonly billing_repository: BillingRepository, ) {} async bill_customer(customer_id: string, amount: number) { const balance = await this.billing_repository.get_balance(customer_id); // The balance may change between the time of this check and the update. if (balance === null || balance <p>在 bill_customer 函數中,我們先使用 get_balance 來擷取使用者的餘額。然後,我們檢查餘額是否足夠並使用 set_balance 更新它。 </p> <h2> 交易 </h2> <p>上述程式碼的問題在於,在取得和更新時間之間的餘額可能會改變。為了避免這種情況,我們需要使用<strong>交易</strong>。您可以透過兩種方式處理這個問題:</p>
- 在儲存庫模組中嵌入業務邏輯:這種方法將業務規則與資料庫操作耦合在一起,使測試變得更加困難。
- 在服務模組中使用交易:這可能會導致抽象洩漏,因為服務模組需要明確管理資料庫會話。
相反,我建議採用更乾淨的方法。
交易代碼
處理事務的一個好方法是建立一個在事務中包裝回調的函數。此函數提供了一個會話對象,該對像不會暴露不必要的內部細節,從而防止洩漏抽象。會話物件傳遞給事務中所有與資料庫相關的函數。
實作方法如下:
import { Injectable } from '@nestjs/common'; import postgres, { TransactionSql } from 'postgres'; export type SessionObject = TransactionSql<record unknown>>; @Injectable() export class BillingRepository { constructor( private readonly db_connection: postgres.Sql, ) {} async run_in_session<t>(cb: (sql: SessionObject) => T | Promise<t>) { return await this.db_connection.begin((session) => cb(session)); } async get_balance( customer_id: string, session: postgres.TransactionSql | postgres.Sql = this.db_connection ): Promise<number null> { const rows = await session` SELECT amount FROM balances WHERE customer_id=${customer_id} `; return (rows[0]?.amount) ?? null; } async set_balance( customer_id: string, amount: number, session: postgres.TransactionSql | postgres.Sql = this.db_connection ): Promise<void> { await session` UPDATE balances SET amount=${amount} WHERE customer_id=${customer_id} `; } } </void></number></t></t></record>
在此範例中,run_in_session 函數啟動一個交易並在其中執行回呼。 SessionObject 類型抽象資料庫會話以防止洩漏內部細節。所有與資料庫相關的函數現在都接受會話對象,確保它們可以參與相同事務。
更新的服務模組
服務模組更新為槓桿交易。它看起來像這樣:
import { Injectable } from '@nestjs/common'; import postgres from 'postgres'; @Injectable() export class BillingRepository { constructor( private readonly db_connection: postgres.Sql, ) {} async get_balance(customer_id: string): Promise<number null> { const rows = await this.db_connection` SELECT amount FROM balances WHERE customer_id=${customer_id} `; return (rows[0]?.amount) ?? null; } async set_balance(customer_id: string, amount: number): Promise<void> { await this.db_connection` UPDATE balances SET amount=${amount} WHERE customer_id=${customer_id} `; } } </void></number>
在 bill_customer_transactional 函數中,我們呼叫 run_in_session 並以會話物件作為參數傳遞回調,然後將此參數傳遞給我們呼叫的儲存庫的每個函數。這可確保 get_balance 和 set_balance 在同一事務中運作。如果兩次呼叫之間的餘額發生變化,交易將失敗,從而保持資料完整性。
結論
使用事務有效地確保您的資料庫操作保持一致,尤其是在涉及多個步驟時。我概述的方法可以幫助您在不洩漏抽象的情況下管理事務,從而使您的程式碼更易於維護。嘗試在您的下一個專案中實現此模式,以保持邏輯清晰和資料安全!
感謝您的閱讀!
?喜歡這篇文章別忘了按讚嗎?
聯絡方式
如果您喜歡這篇文章,請隨時在 LinkedIn 上聯繫並在 Twitter 上關注我。
訂閱我的郵件清單:https://sergedevs.com
一定要喜歡並關注嗎?
以上是如何在 TypeScript 中編寫事務資料庫調用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

記事本++7.3.1
好用且免費的程式碼編輯器