多線程下 到底是事務內部開啟鎖 還是先加鎖再開啟事務?

前言

不知大家是否有觀察到一個最常見的錯誤:

先開啟事務,然后針對資源加鎖,操作資源,然后釋放鎖,最后提交事務

你是否發現了在這樣的場景下會出現并發安全的問題?
(提示:一個線程A在事務內部釋放鎖,另一個線程B拿到了鎖,線程B看不到線程A的操作 導致 線程B 重復執行線程A已經對資源進行的操作)

用一個業務場景去說明

用一個電商系統的訂單處理場景來具體說明這個“事務沒有完全被鎖包住”會導致的問題。

需求: 用戶點擊“下單”按鈕后,后臺要:

檢查該用戶是否已經提交過該訂單(防重復下單)

如果沒有,就創建訂單

并扣減庫存

錯誤的業務代碼:

@Transactional
public void createOrder(String userId, String orderNo) {if (!orderService.hasOrdered(orderNo)) {synchronized (("lock:" + orderNo).intern()) {// 鎖內邏輯// 此處加鎖}// 鎖釋放了,但事務還沒提交orderService.save(orderNo);  // 保存訂單productService.decreaseStock(); // 扣減庫存}
}

1、線程A

開啟事務

查詢:是否已下單?→ 查詢不到(因為數據庫未提交)

執行下單邏輯:準備插入訂單

!! 鎖在事務內部,提前釋放

事務還沒提交!

2、線程B

緊接著執行相同操作

開啟事務

查詢:是否已下單?→ 同樣查詢不到(線程A沒提交)

執行下單邏輯:插入重復訂單、扣減庫存

提交事務

最終結果

因為 數據庫在**“讀已提交**”隔離級別下,線程B看不到線程A未提交的插入

又因為加鎖只包了業務邏輯而不是整個事務范圍

所以鎖一旦提前釋放,線程B就能并發進來了
線程A和線程B都成功下了單

結果就是 重復支付 / 重復下單

改進

public void createOrderSafe(String userId, String orderNo) {synchronized (("lock:" + orderNo).intern()) { // 線程B被阻塞doCreateOrder(userId, orderNo);           // 鎖保護整個事務 內部是本地事務}
}

或者微服務中 使用redis分布式鎖

RLock lock = redissonClient.getLock("order:" + orderNo);
if (lock.tryLock()) {try {// 事務中執行訂單判斷與插入} finally {lock.unlock(); // 鎖直到事務結束才釋放}
}

總結

鎖放在事務外部

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87095.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87095.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87095.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Javascript解耦,以及Javascript學習網站推薦

一、學習網站推薦 解構 - JavaScript | MDN 界面如下,既有知識點,也有在線編譯器執行代碼。初學者可以看看 二、Javascript什么是解構 解構語法是一種 Javascript 語法。可以將數組中的值或對象的屬性取出,賦值給其他變量。它可以在接收數…

Java大模型開發入門 (11/15):讓AI自主行動 - 初探LangChain4j中的智能體(Agents)

前言 在過去的十篇文章里,我們已經打造出了一個相當強大的AI應用。它有記憶,能進行多輪對話;它有知識,能通過RAG回答關于我們私有文檔的問題。它就像一個博學的“學者”,你可以向它請教任何在其知識范圍內的問題。 但…

Qt KDReports詳解與使用

Qt KDReports詳解與使用 一、KD Reports 簡介二、安裝與配置三、核心功能與使用1、創建基礎報表2、添加表格數據3、導出為 PDF4、XML報表定義 四、高級功能1、動態數據綁定2、自定義圖表3、模板化設計4、頁眉頁腳設置 五、常見問題六、總結七、實際應用示例:發票生成…

Spring Cloud 原生中間件

📝 代碼記錄 Consul(服務注冊與發現 分布式配置管理) 擁有服務治理功能,實現微服務之間的動態注冊與發現 ?不在使用Eureka:1. 停更進維 2. 注冊中心獨立且和微服務功能解耦 Consul官網 Spring官方介紹 三個注冊中…

CMake實踐: 以開源庫QSimpleUpdater為例,詳細講解編譯、查找依賴等全過程

目錄 1.環境和工具 2.CMake編譯 3.查找依賴文件 3.1.windeployqt 3.2.dumpbin 4.總結 相關鏈接 QSimpleUpdater:解鎖 Qt 應用自動更新的全新姿勢-CSDN博客 1.環境和工具 windows 11, x64 Qt5.12.12或Qt5.15.2 CMake 4.0.2 干凈的windows 7,最好是…

WordToCard制作高考志愿填報攻略小卡片【豆包版】

一、什么是WordToCard WordToCard是一個免費的工具,能夠將Word文檔自動轉換為美觀的知識卡片或圖文海報。以下是它的主要特點: 功能優勢 格式支持:支持標題、列表、表格、LaTeX公式等多種格式。模板豐富:提供多種風格的模板&am…

什么是PostCSS

PostCSS是一個用 JavaScript 工具和插件轉換 CSS 代碼的工具 PostCSS是基于 JavaScript 的 CSS 轉換引擎,通過插件系統對 CSS 進行現代化處理,PostCSS 不是預處理器,而是 CSS 的編譯器工具鏈,如同 Babel 之于 JavaScript&#xf…

游戲引擎學習第315天:取消排序鍵的反向順序

倉庫:https://gitee.com/mrxiao_com/2d_game_8 必須保證代碼能跟上不然調試很麻煩 回顧并為今天定調 目前正處于對引擎中 Z 軸處理方式進行修改的階段。上次我們暫停在一個節點,當時我們希望不再讓所有屏幕上的精靈都必須通過同一個排序路徑進行排序。我們想要將…

MySQL EXPLAIN 詳解

MySQL EXPLAIN 詳解:掌握 SQL 性能優化的關鍵工具 在日常數據庫開發和優化過程中,很多開發者會遇到 SQL 查詢變慢、索引未命中等問題。MySQL 提供了一個非常實用的工具 —— EXPLAIN 關鍵字,它可以幫助我們分析 SQL 查詢的執行計劃,識別潛在的性能瓶頸,從而有針對性地進行…

k8s使用私有harbor鏡像源

前言 在node上手動執行命令可以正常從harbor拉取鏡像,但是用k8s不行,使用kubectl describe pods xxx 提示未授權 unauthorized to access repository。 處理方法 創建一個secrete資源對象。以下示例中 registry-harbor 為secret資源對象的名稱。除了郵…

AI繪畫能發展到企業大規模使用的地步么?

1 技術演進與當前成熟度 AI繪畫技術經歷了從實驗室概念到商業級工具的蛻變過程。早期技術受限于模型坍縮等問題,難以滿足商業需求。關鍵突破出現在新型生成模型的應用,大幅提升生成速度至30秒內,在畫面邏輯性和風格多樣性方面實現質的飛躍。…

使用MyBatis-Plus實現數據權限功能

什么是數據權限 數據權限是指系統根據用戶的角色、職位或其他屬性,控制用戶能夠訪問的數據范圍。與傳統的功能權限(菜單、按鈕權限)不同,數據權限關注的是數據行級別的訪問控制。 常見的數據權限控制方式包括: 部門數…

大模型——Dify 與 Browser-use 結合使用

大模型——Dify 與 Browser-use 結合使用 Dify 與 Browser-use 的結合使用,能夠通過 AI 決策與自動化交互的協同,構建智能化、場景化的業務流程。 以下是兩者的整合思路與技術落地方案: 一、核心組合邏輯 分工定位 Dify:作為AI模型調度中樞,負責自然語言理解、決策生成、…

transformer demo

import torch import torch.nn as nn import torch.nn.functional as F import math import numpy as np import pytestclass PositionalEncoding(nn.Module):def __init__(self, d_model, max_seq_length5000):super(PositionalEncoding, self).__init__()# 創建位置編碼矩陣p…

centos 8.3(阿里云服務器)mariadb由系統自帶版本(10.3)升級到10.6

1. 備份數據庫 在進行任何升級操作前,務必備份所有數據庫: mysqldump -u root -p --all-databases > all_databases_backup.sql # 或者為每個重要數據庫單獨備份 mysqldump -u root -p db_name1 > db_name1_backup.sql mysqldump -u root -p db…

如何穩定地更新你的大模型知識(算法篇)

目錄 在線強化學習的穩定知識獲取機制:算法優化與數據策略一、算法層面的穩定性控制機制二、數據處理策略的穩定性保障三、訓練過程中的漸進式優化策略四、環境設計與反饋機制的穩定性影響五、穩定性保障的綜合應用策略六、總結與展望通過強化學習來讓大模型學習高層語義知識,…

圖的遍歷模板

圖的遍歷 BFS 求距離 #include<bits/stdc.h>using namespace std;int n, m, k,q[20001],dist[20001]; vector<int> edge[20001];int main(){scanf("%d%d%d",&n,&m,&k);for (int i 1;i<m;i){int x,y;scanf("%d%d",&x,&am…

Java集合 - LinkedList底層源碼解析

以下是基于 JDK 8 的 LinkedList 深度源碼解析&#xff0c;涵蓋其數據結構、核心方法實現、性能特點及使用場景。我們從 類結構、Node節點、插入/刪除/訪問操作、線程安全、性能對比 等角度進行詳細分析 一、類結構與繼承關系 1. 類定義 public class LinkedList<E> e…

Pytorch 卷積神經網絡參數說明一

系列文章目錄 文章目錄 系列文章目錄前言一、卷積層的定義1.常見的卷積操作2. 感受野3. 如何理解參數量和計算量4.如何減少計算量和參數量 二、神經網絡結構&#xff1a;有些層前面文章說過&#xff0c;不全講1. 池化層&#xff08;下采樣&#xff09;2. 上采樣3. 激活層、BN層…

C++ 中的 iostream 庫:cin/cout 基本用法

iostream 是 C 標準庫中用于輸入輸出操作的核心庫&#xff0c;它基于面向對象的設計&#xff0c;提供了比 C 語言的 stdio.h 更強大、更安全的 I/O 功能。下面詳細介紹 iostream 庫中最常用的輸入輸出工具&#xff1a;cin 和 cout。 一、 基本概念 iostream 庫&#xff1a;包…