關係型資料庫事務一:概念

来源:https://www.cnblogs.com/nativestack/archive/2018/07/16/ricky_datasys01.html
-Advertisement-
Play Games

筆者在寫上一篇文章Java併發簡介 中腦子裡面同時也閃爍著,程式中有併發問題,那資料庫中也有類似問題嗎? 讓我們一起看一下吧! 事務是將一組讀寫操作組合在一起形成一個邏輯單元。這些操作要麼全部執行成功提交(commit),要麼全部中止失敗(abort,rollback),不會留下一個中間狀態的爛攤子 ...


筆者在寫上一篇文章Java併發簡介 中腦子裡面同時也閃爍著,程式中有併發問題,那資料庫中也有類似問題嗎? 讓我們一起看一下吧!

事務是將一組讀寫操作組合在一起形成一個邏輯單元。這些操作要麼全部執行成功提交(commit),要麼全部中止失敗(abort,rollback),不會留下一個中間狀態的爛攤子。所以,失敗後程式可以安全的重試,分析原因等。 相反,如果沒有對事務的支持,資料庫可能持久化很多中間狀態,留下無法解釋的業務,開發人員處理起來也很麻煩。所以,事務是為了簡化編程,提供數據安全/正確性/一致性。當然,任何便利都是有代價的,事務也有一些問題,所以NoSQL資料庫,分散式資料庫在某種程度上會弱化事務。有些甚至完全放棄事務。Let's dig into most of the aspects of transaction!

ACID特性

談到事務,都想到ACID。每個字母分別代表原子性(Atomicity),一致性(Consistency),隔離性(Isolation),持久性 (Durability)。搞清楚了ACID,就相當於搞清楚了事務的精髓。

原子性(Atomicity)

和JAVA併發中的原子性不同,程式中的原子性代表被規定的原子操作的中間狀態不會被別的併發線程看到。而這裡的原子性更多的是表達失敗和成功的結果。併發問題是在隔離性(Isolation)裡面談及的。當有多次寫入的時候,中間可能會出現各種問題(進程崩潰,斷電,網路故障,硬碟滿,違反約束等),如果這些操作被分配到一個事務中, 那麼提交(commit)動作會失敗,事務隨即中止,但是資料庫會保證故障之前對系統做的任何修改,寫入都被撤銷。隨後,可以安全地重試失敗的事務。 如果沒有原子性保障,而把這種失敗處理交給開發人員或者客戶端處理,那麼將是非常困難的,客戶端很難知道哪些被寫入了資料庫,而重試則更是雪上加霜,讓錯誤進一步擴大。

一致性(Consistency)

有人認為,一致性是強加在ACID里湊數的。因為這個東西不是資料庫要保證的,而是應用程式需要定義和關註的。有一些道理。
我們經常認為,主外鍵約束達成了某種一致性,你不能在子表裡面插入父表沒有的鍵值,這是資料庫給保證了一致性,但是這種一致性也是根據業務由開發人員定義的。如果你向資料庫插入違反業務邏輯的假數據,資料庫並沒有這種約束阻止你。所以,一致性是通過事務的其他特性(原子性,隔離性)達成的,它並不屬於資料庫和事務的屬性。

隔離性(Isolation)

當多個客戶端同時訪問資料庫的同一對象時,就會有併發問題,或者叫競態條件(race condition)。下圖1的簡單計數器例子說明瞭此問題,當兩個客戶端同時給計數器加1的時候,我們期望的結果如同他們串列化完成一樣,可是在併發環境中沒有一些保證的話,結果會像是丟失更新(lost update)一樣,實際只增加了一次。

隔離性保證同時執行的事務是相互隔離的,它們不能互相影響。簡言之,一個事務只能看到另一個事務開始之前或者結束之後的結果,不能看到任何中間狀態,反之亦然。結果就如同他們串列化(Serializability)完成一樣,儘管實際上它們是併發運行的。隔離性分好幾種級別,每一種隔離級別都在權衡性能和某種安全保障,This is a kind of trade-off. 我們在下一篇文章會分析這些隔離級別。

持久性(Durability)

持久性保證當用戶提交事務並完成後,數據最終會被永久安全地保存到磁碟中,而不管是否發生故障或者系統崩潰。在單節點的資料庫中,通過日誌,可以保證系統在崩潰之後起來,依然能夠自動完成一致性和持久化的要求(rollforward,rollback)。通過歸檔日誌,當磁碟損壞後,還能恢復到某個時間點。為了進一步保證持久性,對日誌和歸檔日誌可以進行多副本設置。

當然,沒有完美的持久性,如果由於機房起火,所有數據(備份,日誌等)都銷毀。所以,更嚴格的保證可以通過異地備份實現,但也不是完美的,不抬杠了。

單對象和多對象操作

我們舉例子來說明一下事務在單對象和多對象操作中的作用。

多對象操作

下圖(圖2)是一個關於未讀消息數量的例子,當用戶有新郵件時,則會使相應的計數器加1,用戶看了郵件後,則計數器減1。 消息和計數器為兩個不同對象。我們假設初始狀態沒有新郵件,計數器為0。 如果沒有事務的話,用戶2看到了自己有一份新郵件,但是未讀郵件數量卻是0. 因為用戶2看到了用戶1未提交的寫入(插入的新郵件),稱作臟讀。事務的隔離性可以解決這種問題。

如果新郵件到來時,用戶1在更新計數器的時候,發生某種崩潰而失敗,那麼郵箱和計數器則會不一致,失去同步(見圖3)。 事務的原子性可以保證:如果計數器更新失敗,事務會中止,插入的新郵件會被撤銷(回滾). 介於BEGIN TRANSACTION 和 COMMIT之間的代碼被認為在同一事務之中。

另一方面,許多非關係資料庫並沒有將多個操作組合一起的方法,即使存在錶面的多對象API(例如,鍵值存儲可能具有在一個操作中更新多個鍵的操作),但並不意味它具有事務的特性,該操作可能在一些鍵上更新成功,在其他鍵上失敗,這種部分更新也就體現在了資料庫端。

單對象寫入

對於單對象的寫入,原子性和隔離性是毋庸置疑的,如果你正在向資料庫寫入一個20KB的JSON文檔:

  • 如果在發送第一個10KB之後網路中斷,資料庫是否存儲不可解析的10KB JSON片段?
  • 如果在覆蓋前一個文檔的過程中斷電,是否最終將新舊值拼在一起?
  • 如果另一個客戶端在寫入的過程中讀取文檔,是否看到部分更新的值?

這些問題非常令人困惑,所以存儲引擎幾乎都實現了:對單節點上的單個對象(比如鍵值對)上提供原子性和隔離性。原子性可以通過日誌來實現崩潰恢復,通過每個對象上的鎖來實現隔離(每次只允許一個線程訪問對象)。Apache HBase就是一個例子。

一些資料庫也提供了複雜一些的原子操作,如自增操作(定義的自增主鍵)。還有CAS操作(比較和設置),當值沒有被其他人修改過時,才允許執行寫操作。這些保證很有用,防止在多客戶端同時寫入一個對象時丟失更新。但它們不是通常意義上的事務。這些單一對象保證被稱作“輕量級事務”,甚至出於營銷目的被稱為“ACID”,是有誤導性的。事務通常被理解為:將多個對象上的多個操作合併為一個執行單元的機制。   

仔細想想,如果從事務的角度去理解多線程編程中的計數器自增問題,更多的不是因為沒有原子性,而是因為沒有隔離性,所以才靠同步(鎖),volatile等機制。本質上,都是一樣的(併發引起的問題)。

在你的應用中,單對象的保證是否足夠,多對象操作的協同是否必須?  我們不能簡單地實現功能來交差,更重要的是要正確地實現。錯誤雖然不可避免,但許多軟體開發人員傾向於只考慮樂觀情況,而不是錯誤處理的複雜性。

事務中止重試

之前我們說過,事務中止會回滾事務開始到中止之前的寫入,因此可以安全地重試,但也不夠完美

  • 如果事務執行成功,但是由於網路故障,造成成功消息沒有被返回給客戶端(客戶端認為事務沒有成功),那麼事務會被導致執行兩次。(通過應用排除)
  • 如果錯誤是由於負載過大造成,重試會將問題變得更糟糕。可以限制重試次數,並單獨處理與過載相關的錯誤。
  • 在發生永久性錯誤(例如違法約束)後重試是毫無意義的。僅在臨時性錯誤(死鎖,網路故障等)後才重試。
  • 如果事務對外部系統有影響,比如發送郵件。 重試則很可能造成重覆給用戶發郵件

 下一節我們討論隔離級別


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

-Advertisement-
Play Games
更多相關文章
  • 自己嘗試安裝SQL Server集群和配置AlwaysOn可用性組,伺服器系統是Windows Server 2012 R2,SQL Server是2014企業版,我的環境是一臺伺服器,然後用Hyper創建了兩台虛擬機也是Windows Server 2012 R2, 參照這個文章進行配置 http ...
  • 目前大數據行業異常火爆,不少人都對大數據充滿了興趣,其中有大部分人都是之前沒有接觸過電腦技術的,對編程語言也不太瞭解,那是不是這部分零基礎的朋友就學不了大數據了呢?答案當然是否定的。大數據學習並不是高深莫測的,雖然它並沒有多簡單,但是通過努力,零基礎的朋友也是完全可以掌握大數據的。 推薦一個大數據 ...
  • 外鍵是什麼? 如果有兩張表:A,B。 A表中有欄位:c,d,e,f; B表中有d,g,h,i。 那麼,d欄位就可以叫外鍵。對於A來說,d是A的欄位;對於B來說,d是B的主鍵。 ...
  • 環境介紹,VIP 172.16.128.239在172.16.128.240上,我們是基於172.16.128.240和172.16.128.241做的keepalived。MGR為多主模式。我們考慮使用中間件能夠實現MGR的讀寫分離。中間件選型為Atlas,Atlas是360團隊開源的一套基於My ...
  • 如果您的Hadoop項目將有新的突破,那麼它必定與下邊介紹的七種常見項目很相像。 有一句古老的格言是這樣說的,如果你向某人提供你的全部支持和金融支持去做一些不同的和創新的事情,他們最終卻會做別人正在做的事情。如比較火爆的Hadoop、Spark和Storm,每個人都認為他們正在做一些與這些新的大數... ...
  • 大數據人工智慧淘寶天貓雙十一幕後:實時可視化查詢大屏 這張圖片來源於天貓雙十一數據直播,來自大數據可視化的魅力 【what】什麼是數據可視化? 塔夫特所說,“圖形表現數據。實際上比傳統的統計分析法更加精確和有啟發性。”對於廣大的編輯、設計師、運營分析師、大數據研究者等等都需要從不同維度、不同層面、不 ...
  • 1、表鎖和行鎖 表鎖和行鎖鎖的粒度不一樣,表鎖鎖住的是一整張表,行鎖鎖住的是表中的一行數據。 InnoDB使用的是行級鎖,MyISAM使用的是表級鎖。 註意:在InnoDB中,例如模糊查詢select * from tb where name like 'lin%'的時候也會鎖住一整張表。 2、共用 ...
  • 有表tb, 如下:id value 1 aa,bb2 aaa,bbb,ccc欲按id,分拆value列, 分拆後結果如下:id value 1 aa1 bb2 aaa2 bbb2 ccc --方法1.使用xml完成SELECT A.id, B.value FROM( SELECT id, [valu ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...