資料庫中的事務和併發問題探討

来源:http://www.cnblogs.com/zhu-wj/archive/2017/06/22/7067455.html
-Advertisement-
Play Games

理解資料庫中的事務及其併發過程中的各種限制對於合理的解決數據問題據有著重要意義,否則極有可能出現非常難以排查的由數據導致的程式bug。 ...


資料庫中的事務和併發問題探討

引子

最近有同事寫了段代碼,負責創建訂單的邏輯,代碼審查時發現可能會有併發的問題。同事並不認同,他認為他的邏輯是寫在存儲過程中的,應該沒有問題。

代碼的邏輯大概是(偽代碼):

begin transaction

if 查詢到客戶存在進行中的訂單
     rollback transaction

if 查詢到設備存在進行中的訂單
     rollback transaction
    
插入訂單

commit transaction

下麵針對這個邏輯進行分析,為什麼這個事務會出現併發問題。

事務概述

首先,提出兩個問題,然後帶著問題討論事務相關的知識點,最後來解決這兩個問題並回答前文的問題。

第一個問題,事務是否可以併發?

第二個問題,資料庫是怎麼隔離事務的?

事務的表現特性

資料庫中執行事務涉及到很多方面,包括如何處理臨界資源,如何加鎖解鎖等等。但是無論事務如何執行,都需要保證以下幾個特性:

  • 原子性
  • 一致性
  • 隔離性
  • 持久性

原子性:所有的操作是一個邏輯單元,要麼都提交成功,要麼就都失敗;

一致性:只有合法的數據被寫入資料庫,否則事務回滾到最初的狀態;

隔離性:允許多個事務同時進行,而不會破壞數據的正確性和完整性;

持久性:事務結束後,已經提交的結果被固化保存。

資料庫的各種鎖

  1. 共用鎖

共用鎖用於非獨占的業務,允許多個事務同時讀取鎖定的資源,但是不允許資源被更新。

  • 加鎖時機:執行select語句時預設會被加上
  • 解鎖時機:執行完讀取後預設解除
  • 與其他鎖相容性:數據上被設置了共用鎖,則不會允許再增加共用鎖和獨占鎖
  • 併發性能:具有良好的併發性能
  1. 排他鎖

排他鎖,也叫獨占鎖。顧名思義,被排他鎖鎖定的資源不會允許其他事務進行任何操作。

  • 加鎖時機:執行insert,update,delete時預設會被加上
  • 解鎖時機:事務結束才能解除
  • 相容性:如果數據上有其他鎖,不能增加獨占鎖;同樣獨占鎖存在時也不會允許增加其他鎖
  • 併發性能:其他事務必須等待前一個事務結束後才能執行,不能併發,只能串列
  1. 更新鎖

在更新的初始階段用於鎖定所需要的資源,防止在讀取階段使用共用鎖造成死鎖。

  • 加鎖時機:執行update時,使用更新鎖鎖定相關資源
  • 解鎖時機:讀取完畢,執行更新操作時,更新鎖升級為獨占鎖
  • 相容性:更新鎖與共用鎖相容,即可以同時存在更新鎖和共用鎖,但只能有一個更新鎖
  • 併發性能:更新初期的讀取階段可以允許其他事務讀取資源,允許有限的併發;後期對資源進行獨占時不允許併發。

事務隔離級別

通用的事務隔離級別有四種,SQL Server還有另外擴展出來的級別,在此不多介紹。

  1. Serializable(串列化)

工作方式類似於可重覆讀。但它不僅會鎖定受影響的數據,還會鎖定這個範圍。這就阻止了新數據插入查詢所涉及的範圍,這種情況可以導致幻像讀。

  1. Repeatable Read(可重覆讀)

像已提交讀級別那樣讀數據,但會保持共用鎖直到事務結束。

  1. Read Commit

只讀取提交的數據並等待其他事務釋放排他鎖。讀數據的共用鎖在讀操作完成後立即釋放。已提交讀是SQL Server的預設隔離級別。

  1. Read Uncommited

在讀數據時不會檢查或使用任何鎖。因此,在這種隔離級別中可能讀取到沒有提交的數據。

回答前文的問題

第一個問題,事務是否可以併發?

答案是肯定的,資料庫中為了提高性能,允許同時進行多個事務操作,這個事務跟發起方式無關,使用存儲過程發起,或者使用代碼發起,又或者使用普通的SQL語句發起並沒有什麼區別。

第二個問題,資料庫是怎麼隔離事務的?

要回答這個問題,先要理解資料庫中的鎖機制和資料庫事務隔離級別。資料庫中的鎖可以分為三種類型:共用鎖、獨占鎖和更新鎖。使用不同級別的鎖並配合不同的鎖定範圍已達到不同的事務隔離級別併在此基礎上併發或串列執行事務。

第三個問題,為什麼本文開頭的事務會存在併發問題?

因為事務的開始執行的是select,select使用的是共用鎖,有可能併發的事務在同一時間執行select導致同時認為自己都是合法操作,而排隊執行後續的事務。結果導致了實際上就有可能插入重覆的數據,比如只剩下一個商品,卻創建了兩個銷售訂單。

如何防止併發問題

  1. 在事務中

根據前文所講,使用insert,update或delete可以在預設事務級別人為造成事務串列化,因此可以在事務內部一開始都使用update更新一條公共的數據,這樣的話同類型的事務都會串列化,然後再增加一個判斷語句,用於判斷後續的事務內容是否應該執行。這樣足以確保所有的操作都按照合理合法,唯一的缺點是可能造成性能問題。

  1. 在事務外

現在分散式的系統越來越多,但是再分佈的系統也會有些共用資源,比如redis或zookeeper,可以利用redis或者zookeeper造一些分散式的鎖(此類屬於其他博文內容,在此不再展開)。利用事務外部的鎖將同類型的事務做一些串列化處理,再配合事務內部的檢查機制,足以確保解決事務的併發問題。

參考資料


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 測試提了一個bug,在360瀏覽器相容模式下,刪除頁面數據需要手動刷新瀏覽器才能看到最新的數據。首先要復現當時的問題,很容易就復現了,但是發現在360瀏覽器相容模式下無法打開開發者工具。好在經過反覆重裝之後,終於打開了開發者工具,經過跟蹤發現,第一次刪除數據時可以正常刷新,第二次或以後的刪除將無法刷 ...
  • Vue實戰Vue-cli項目構建(Vue+webpack系列之一) ...
  • 最近在研究 stm32f429i disc0 的 device tree source code, 並且 參造 Devicetree Specification Release 0.1, 在 dts source code 中發現有一個 clock cells property, 但在 dts sp ...
  • HDFS是Hadoop應用程式使用的主要分散式存儲。HDFS集群主要由管理文件系統元數據的NameNode和存儲實際數據的DataNodes組成,HDFS架構圖描述了NameNode,DataNode和客戶端之間的基本交互。客戶端聯繫NameNode進行文件元數據或文件修改,並直接使用DataNod ...
  • Oracle以dba身份登陸 sqlplus / as sysdba; 1 --查詢創建的序列信息 2 select * from user_sequences; 3 4 --查詢序列的當前值 5 select SQ_TEACHER_TNO.CURRVAL from dual; 6 7 --查詢序列 ...
  • (前段時間在做嵌入式的課程設計,特將學習心得整理如下) 一、開發工具及環境介紹 1、ARM處理器 ARM處理器是一個32位元精簡指令集(RISC)處理器架構,其廣泛地使用在許多嵌入式系統設計。 ARM處理器特點: 2、交叉編譯環境 2.1、交叉編譯 交叉編譯(cross-compilation)是指 ...
  • 使用linux虛擬機時,通常會用到yum命令來安裝軟體,然而這個命令需要連外網下載軟體,用maven下載jar包也需要外網。虛擬機在內網可以互相ping通,然而ping不了外網,於是通過試驗,終於找到瞭解決方案: 1.在物理機的cmd命令行中,使用ipconfig命令,查看IP配置,由圖可知,物理機 ...
  • 1、可選參數和命名參數 1.1可選參數 語法: [修飾符] 返回類型 方法名(必選參數n,可選參數n) 註意: 1.必選參數可以不存在,也可以有多個;可選參數可以有1個或多個 2.可選參數必須放在必選參數之後 3.可選參數在定義時需要賦初始值 4.可選參數之間也需要使用,進行分隔 5.調用可選參數時 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...