」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 如何使用 Java 和 PostgreSQL 處理競爭條件

如何使用 Java 和 PostgreSQL 處理競爭條件

發佈於2024-08-01
瀏覽:873

How to deal with race conditions using Java and PostgreSQL

使用鎖來控制資料庫並發

想像一下,您正在開發一個電子商務系統,成千上萬的人試圖同時購買最後剩下的產品。然而,他們中的許多人可以繼續結帳並完成訂單。當您檢查庫存時,您的產品數量為負數。這是怎麼可能的,你該如何解決這個問題?

讓我們來編碼吧!您可能想到的第一件事是在結帳前檢查庫存。也許是這樣的:

public void validateAndDecreaseSolution(long productId, int quantity {
    Optional stockByProductId = 
 stockRepository.findStockByProductId(productId);

    int stock = stockByProductId.orElseThrow().getStock();
    int possibleStock = stock - quantity;

    if (stock 



您可以使用此驗證,但是當我們談論每秒數百、數千、數百萬甚至數十個請求時,此驗證是不夠的。當 10 個請求同時到達這段程式碼並且資料庫為 stockByProductId 傳回相同的值時,您的程式碼將會崩潰。在我們進行此驗證時,您需要一種方法來阻止其他請求。

第一個解決方案 - 用於更新

在 SELECT 上新增鎖定語句。在此範例中,我使用 Spring Data 的 FOR UPDATE 來完成此操作。正如 PostgreSQL 文件所述

FOR UPDATE 導致 SELECT 語句檢索的行被鎖定,就像要更新一樣。這可以防止它們被其他事務修改或刪除,直到目前事務結束。

@Query(value = "SELECT * FROM stocks s WHERE s.product_id = ?1 FOR UPDATE", nativeQuery = true)
Optional findStockByProductIdWithLock(Long productId);
public void validateAndDecreaseSolution1(long productId, int quantity) {
    Optional stockByProductId = stockRepository.findStockByProductIdWithLock(productId);

    // ... validate

    stockRepository.decreaseStock(productId, quantity);
}

所有使用產品ID對stocks表的請求都會等待,直到實際事務完成。這裡的目標是確保您獲得股票的最新更新價值。

第二個解決方案 - pg_advisory_xact_lock

此解決方案與上一個類似,但您可以選擇鎖定鍵是什麼。我們將鎖定整個交易,直到完成所有驗證和庫存減量的處理。

public void acquireLockAndDecreaseSolution2(long productId, int quantity) {
    Query nativeQuery = entityManager.createNativeQuery("select pg_advisory_xact_lock(:lockId)");
    nativeQuery.setParameter("lockId", productId);
    nativeQuery.getSingleResult();

    Optional stockByProductId = stockRepository.findStockByProductId(productId);

    // check stock and throws exception if it is necessary

    stockRepository.decreaseStock(productId, quantity);
}

本次交易結束後,下一次請求只會與同ID的商品互動。

第三種解決方案 - WHERE 子句

在這種情況下,我們不會鎖定行或事務。讓我們允許此事務繼續進行,直到更新語句為止。請注意最後一個條件:庫存 > 0。這將不允許我們的庫存小於零。因此,如果兩個人嘗試同時購買,其中一個人會收到錯誤,因為我們的資料庫不允許庫存

@Transactional
@Modifying
@Query(nativeQuery = true, value = "UPDATE stocks SET stock = stock - :quantity WHERE product_id = :productId AND stock > 0")
int decreaseStockWhereQuantityGreaterThanZero(@Param("productId") Long productId, @Param("quantity") int quantity);

結論

第一個和第二個解決方案使用悲觀鎖定作為策略。第三是樂觀鎖。當您在執行涉及某個資源的任何任務時希望限制對該資源的存取時,可以使用悲觀鎖定策略。在您完成進程之前,目標資源將被鎖定以進行任何其他存取。小心死鎖!

使用樂觀鎖,您可以對相同資源執行各種查詢,而不會出現任何阻塞。當衝突不太可能發生時使用它。通常,您會有一個與您的行相關的版本,當您更新該行時,資料庫會將您的行版本與資料庫中的行版本進行比較。如果兩者相等,則變更將成功。如果沒有,您必須重試。正如您所看到的,我在本文中沒有使用任何版本行,但我的第三個解決方案不會阻止任何請求並使用 stock > 0 條件控制並發性。

如果想看完整的程式碼,可以查看我的GitHub。

還有許多其他策略來實現悲觀鎖定和樂觀鎖定,例如您可以搜尋更多有關 FOR UPDATE WITH SKIP LOCKED 的內容。

版本聲明 本文轉載於:https://dev.to/ramoncunha/how-to-deal-with-race-conditions-using-java-and-postgresql-4jk6?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何為 DOM 元素產生精確的 CSS 路徑?
    如何為 DOM 元素產生精確的 CSS 路徑?
    以增強的精度從 DOM 元素檢索 CSS 路徑提供的函數嘗試為給定 DOM 元素生成 CSS 路徑。然而,它的輸出缺乏特異性,無法捕捉元素在其兄弟元素中的位置。為了解決這個問題,我們需要一個更複雜的方法。 改進的 CSS 路徑函數下面介紹的增強函數解決了原來的限制:var cssPath = fun...
    程式設計 發佈於2024-11-03
  • 如何將單一 Python 字典寫入具有精確標題和值行的 CSV 檔案?
    如何將單一 Python 字典寫入具有精確標題和值行的 CSV 檔案?
    探索將Python 字典寫入CSV 文件的細微差別您對將Python 字典無縫寫入CSV 文件的追求給您帶來了意想不到的挑戰。雖然您設想在作為標題的字典鍵和作為第二行的值之間進行清晰的劃分,但您目前的方法似乎還不夠。讓我們深入細節,解鎖解決方案。 問題在於方法的選擇。 DictWriter.writ...
    程式設計 發佈於2024-11-03
  • 如何處理 Go 中延遲函數的錯誤回傳值?
    如何處理 Go 中延遲函數的錯誤回傳值?
    處理Go 中返回值錯誤的延遲函數當返回變數的函數在沒有延遲的情況下被延遲時,gometalinter 和errcheck 正確地發出警告檢查其回傳的錯誤。這可能會導致未處理的錯誤和潛在的運行時問題。 處理這種情況的習慣用法不是推遲函數本身,而是將其包裝在另一個檢查返回值的函數中。這是一個例子:def...
    程式設計 發佈於2024-11-03
  • 為什麼程式設計師不能總是記住程式碼:背後的科學
    為什麼程式設計師不能總是記住程式碼:背後的科學
    如果您曾經想知道為什麼程式設計師很難回憶起他們編寫的確切程式碼,那麼您並不孤單。儘管花了數小時編碼,許多開發人員經常忘記細節。這並不是因為缺乏知識或經驗,而是因為工作本身的本質。讓我們來探究一下這種現象背後的原因。 程式設計的本質 透過記憶解決問題 這比僅僅記憶語法...
    程式設計 發佈於2024-11-03
  • 你並不孤單:在社群的支持下掌握 Python
    你並不孤單:在社群的支持下掌握 Python
    加入 Python 社群可取得:社群論壇:向經驗豐富的開發者取得支援和建議(如 Stack Overflow)。 Discord 伺服器:即時聊天室,提供即時支援與指導(如 Python Discord)。線上課程與研討會:來自專家的指導,涵蓋各種主題(如 Udemy 上的 Python NumPy...
    程式設計 發佈於2024-11-03
  • 學習夥伴
    學習夥伴
    聊天機器人介面,允許使用者輸入訊息並接收來自 GPT-3.5 語言模型的對話回應。 特徵 用於處理 HTTP 請求的基於 Flask 的 Web 伺服器。 呈現用作使用者介面的基本 HTML 模板 (chat.html)。 透過 POST 請求接受使用者輸入並將其傳送到 OpenAI 的 GP...
    程式設計 發佈於2024-11-03
  • 前端開發 + 資料結構與演算法:DSA 如何為您的 React 應用程式提供動力 ⚡
    前端開發 + 資料結構與演算法:DSA 如何為您的 React 應用程式提供動力 ⚡
    专注于前端的面试通常根本不关心 DSA。 对于我们这些记得在学校/大学学习过 DSA 的人来说,所有的例子都感觉纯粹是算法(有充分的理由),但几乎没有任何例子或指导来说明我们每天使用的产品如何利用这个概念。 “我需要这个吗?” 你已经问过很多次这个问题了,不是吗? ? 以下是您今天可以在 React...
    程式設計 發佈於2024-11-03
  • 為什麼表格行上的框陰影在不同瀏覽器中表現不同?
    為什麼表格行上的框陰影在不同瀏覽器中表現不同?
    跨瀏覽器表行上的框陰影外觀不一致應用於表行() 的CSS 框陰影可能表現出不一致的行為跨各種瀏覽器。儘管 CSS 相同,但某些瀏覽器可能會如預期顯示陰影,而其他瀏覽器則可能不會。 要解決此問題,建議將 Transform 屬性與 box-shadow 屬性結合使用。將scale(1,1)加入tran...
    程式設計 發佈於2024-11-03
  • 探索 PHP 中的並發性和並行性:實作教學和技巧
    探索 PHP 中的並發性和並行性:實作教學和技巧
    理解並發性和平行性對於編寫高效的 PHP 應用程式至關重要,特別是在處理需要同時處理的多個任務或操作時。這是理解和實作 PHP 並發性和平行性的逐步指南,包含實作範例和說明。 1.併發與並行 並發:指系統透過交錯執行同時處理多個任務的能力。這並不一定意味著任務是同時執行的,只是對它...
    程式設計 發佈於2024-11-03
  • ReactJs 與 Angular
    ReactJs 與 Angular
    React 和 Angular 是用于构建 Web 应用程序的两个最流行的框架/库,但它们在关键方面有所不同。以下是 React 和 Angular 之间主要区别的细分: 1. 类型:库与框架 React:一个用于构建用户界面的库,主要关注视图层。它允许开发人员将其与其他库集成以处理...
    程式設計 發佈於2024-11-03
  • 如何使用變數中儲存的類別名稱動態實例化 JavaScript 物件?
    如何使用變數中儲存的類別名稱動態實例化 JavaScript 物件?
    使用動態類別名稱實例化 JavaScript 物件假設您需要使用儲存在變數中的類別名稱實例化 JavaScript 物件。以下是一個說明性範例:// Define the class MyClass = Class.extend({}); // Store the class name in a s...
    程式設計 發佈於2024-11-03
  • Spring Boot 中的 OAuth 驗證:Google 與 GitHub 登入整合指南
    Spring Boot 中的 OAuth 驗證:Google 與 GitHub 登入整合指南
    使用 OAuth 2.0 增强安全性:在 Spring Boot 中实现社交登录 在现代 Web 开发的世界中,保护您的应用程序并使用户的身份验证尽可能顺利是首要任务。这就是 OAuth 2.0 的用武之地——它是一个强大的工具,不仅可以帮助保护您的 API,还可以让用户使用现有帐户从 Google...
    程式設計 發佈於2024-11-03
  • 熱點圖-巴西 vs 義大利世界盃決賽)
    熱點圖-巴西 vs 義大利世界盃決賽)
    在這篇文章中,我開始嘗試使用 Python 和 Seaborn 和 Matplotlib 創建 1970 年世界盃決賽中巴西運動的熱圖 。這個想法是根據那場比賽的比賽風格特徵來代表巴西隊在場上佔據的空間。 1. 繪製場地 場地設計為比例座標(130x90),包括邊線、球門區和中心圈...
    程式設計 發佈於2024-11-03
  • 如何在 C++ 中連接字串文字和字元文字?
    如何在 C++ 中連接字串文字和字元文字?
    C 中的字串文字和字元文字 嘗試在 C 中連接字串文字與字元文字時,可能會出現意外行為。例如:string str = "ab" 'c'; cout << str << endl;此程式碼會產生不可預測的輸出,因為沒有定義「」運算子來組合字串文字和字元...
    程式設計 發佈於2024-11-03
  • 透過「Go 練習挑戰」課程釋放您的演算法潛力
    透過「Go 練習挑戰」課程釋放您的演算法潛力
    透過 LabEx 的「Go Practice Challenges」課程踏上令人興奮的旅程,提升您的程式設計技能。這門綜合課程旨在幫助您掌握解決問題的藝術和提高程式設計效率,為您提供應對各種演算法挑戰的工具和技術。 深入演算法世界 「圍棋實踐挑戰」課程提供了一系列實際挑戰,將突破您...
    程式設計 發佈於2024-11-03

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3