Transaction ACID (轉載)

来源:https://www.cnblogs.com/shenkebky/archive/2018/01/18/8287053.html
-Advertisement-
Play Games

Transaction Transaction 原文出處: 黃勇 Transaction 也就是所謂的事務了,通俗理解就是一件事情。從小,父母就教育我們,做事情要有始有終,不能半途而廢。�0�2事務也是這樣,不能做一般就不做了,要麼做完,要麼就不做。也就是說,事務必須是一個不可分割的整體,就像我們在 ...


Transaction

原文出處: 黃勇   

Transaction 也就是所謂的事務了,通俗理解就是一件事情。從小,父母就教育我們,做事情要有始有終,不能半途而廢。�0�2事務也是這樣,不能做一般就不做了,要麼做完,要麼就不做。也就是說,事務必須是一個不可分割的整體,就像我們在化學課里學到的原子,原子是構成物質的最小單位。於是,人們就歸納出事務的第一個特性:原子性(Atomicity)。我靠,一點都不神秘嘛。

特別是在資料庫領域,事務是一個非常重要的概念,除了原子性以外,它還有一個極其重要的特性,那就是:一致性(Consistency)。也就是說,執行完資料庫操作後,數據不會被破壞。打個比方,如果從 A 賬戶轉賬到 B 賬戶,不可能因為 A 賬戶扣了錢,而 B 賬戶沒有加錢吧。如果出現了這類事情,您一定會非常氣憤,什麼 diao 銀行啊!

當我們編寫了一條 update 語句,提交到資料庫的一剎那間,有可能別人也提交了一條 delete 語句到資料庫中。也許我們都是對同一條記錄進行操作,可以想象,如果不稍加控制,就會出大麻煩來。我們必須保證資料庫操作之間是“隔離”的(線程之間有時也要做到隔離),彼此之間沒有任何干擾。這就是:隔離性(Isolation)

要想真正的做到操作之間完全沒有任何干擾是很難的,於是乎,每天上班打醬油的資料庫專家們,開始動腦筋了,“我們要制定一個規範,讓各個資料庫廠商都支持我們的規範!”,這個規範就是:務隔離級別(Transaction Isolation Level)。能定義出這樣牛逼的規範真的挺不容易的,其實說白了就四個級別:

  1. READ_UNCOMMITTED
  2. READ_COMMITTED
  3. REPEATABLE_READ
  4. SERIALIZABLE

千萬不要去翻譯,那隻是一個代號而已。從上往下,級別越來越高,併發性越來越差,安全性越來越高,反之則反。

當我們執行一條 insert 語句後,資料庫必須要保證有一條數據永久地存放在磁碟中,這個也算事務的一條特性,�0�2它就是:持久性(Durability)

歸納一下,以上一共提到了事務的 4 條特性,把它們的英文單詞首字母合起來就是:ACID,這個就是傳說中的“事務 ACID 特性”!

真的是非常牛逼的特性啊!這 4 條特性,是事務管理的基石,一定要透徹理解。此外還要明確,這四個家伙當中,誰才是老大?

其實想想也就清楚了:原子性是基礎,隔離性是手段,持久性是目的,真正的老大就是一致性。數據不一致了,就相當於“江湖亂套了,流氓戴胸罩”。所以說,這三個小弟都是跟著“一致性”這個老大混,為他全心全意服務。

這四個家伙當中,其實最難理解的反倒不是一致性,而是隔離性。因為它是保證一致性的重要手段,是工具,使用它不能有半點差池,否則後果自負!怪不得資料庫行業專家們都要來研究所謂的事務隔離級別了。其實,定義這四個級別就是為瞭解決數據在高併發下所產生的問題,那又有哪些問題呢?

  1. Dirty Read(臟讀)
  2. Unrepeatable Read(不可重覆讀)
  3. Phantom Read(幻讀)

首先看看“臟讀”,看到“臟”這個字,我就想到了噁心、骯髒。數據怎麼可能臟呢?其實也就是我們經常說的“垃圾數據”了。比如說,有兩個事務,它們在併發執行(也就是競爭)。看看以下這個表格,您一定會明白我在說什麼:

時間 事務 A(存款) 事務 B(取款)
T1 開始事務  
T2   開始事務
T3   查詢餘額(1000 元)
T4   取出 1000 元(餘額 0 元)
T5 查詢餘額(0 元)  
T6   撤銷事務(餘額恢復為 1000 元)
T7 存入 500 元(餘額 500 元)  
T8 提交事務  

餘額應該為 1500 元才對!請看 T5 時間點,事務 A 此時查詢餘額為 0 元,這個數據就是臟數據,它是事務 B 造成的,明顯事務沒有進行隔離,滲過來了,亂套了。

所以臟讀這件事情是非常要不得的,一定要解決掉!讓事務之間隔離起來才是硬道理。

那第 2 條,不可重覆讀又怎麼解釋呢?還是用類似的例子來說明:

時間 事務 A(存款) 事務 B(取款)
T1 開始事務  
T2   開始事務
T3   查詢餘額(1000 元)
T4 查詢餘額(1000 元)  
T5   取出 1000 元(餘額 0 元)
T6   提交事務
T7 查詢餘額(0 元)  

事務 A 其實除了查詢了兩次以外,其他什麼事情都沒有做,結果錢就從 1000 變成 0 了,這就是重覆讀了。可想而知,這是別人乾的,不是我乾的。其實這樣也是合理的,畢竟事務 B 提交了事務,資料庫將結果進行了持久化,所以事務 A 再次讀取自然就發生了變化。

這種現象基本上是可以理解的,但在有些變態的場景下卻是不允許的。畢竟這種現象也是事務之間沒有隔離所造成的,但我們對於這種問題,似乎可以忽略。

最後一條,幻讀。我去!Phantom 這個單詞不就是“幽靈、鬼魂”嗎?剛看到這個單詞時,真的把我的小弟弟都給驚呆了。怪不得這裡要翻譯成“幻讀”了,總不能翻譯成“幽靈讀”、“鬼魂讀”吧。其實意義就是鬼在讀,不是人在讀,或者說搞不清楚為什麼,它就變了,很暈,真的很暈。還是用一個示例來說話吧:

時間 事務 A(統計總存款) 事務 B(存款)
T1 開始事務  
T2   開始事務
T3 統計總存款(10000 元)  
T4   存入 100 元
T5   提交事務
T6 統計總存款(10100 元)  

銀行工作人員,每次統計總存款,都看到不一樣的結果。不過這也確實也挺正常的,總存款增多了,肯定是這個時候有人在存錢。但是如果銀行系統真的這樣設計,那算是玩完了。這同樣也是事務沒有隔離所造成的,但對於大多數應用系統而言,這似乎也是正常的,可以理解,也是允許的。銀行里那些噁心的那些系統,要求非常嚴密,統計的時候,甚至會將所有的其他操作給隔離開,這種隔離級別就算非常高了(估計要到 SERIALIZABLE 級別了)。

歸納一下,以上提到了事務併發所引起的跟讀取數據有關的問題,各用一句話來描述一下:

  1. 臟讀:事務 A 讀取了事務 B 未提交的數據,併在這個基礎上又做了其他操作。
  2. 不可重覆讀:事務 A 讀取了事務 B�0�2已提交的更改數據。
  3. 幻讀:事務 A 讀取了事務 B 已提交的新增數據。

第一條是堅決抵制的,後兩條在大多數情況下可不作考慮。

這就是為什麼必須要有事務隔離級別這個東西了,它就像一面牆一樣,隔離不同的事務。看下麵這個表格,您就清楚了不同的事務隔離級別能處理怎樣的事務併發問題:

事務隔離級別 臟讀 不可重覆讀 幻讀
READ_UNCOMMITTED 允許 允許 允許
READ_COMMITTED 禁止 允許 允許
REPEATABLE_READ 禁止 禁止 允許
SERIALIZABLE 禁止 禁止 禁止

根據您的實際需求,再參考這張表,最後確定事務隔離級別,應該不再是一件難事了。

JDBC 也提供了這四類事務隔離級別,但預設事務隔離級別對不同資料庫產品而言,卻是不一樣的。我們熟知的 MySQL 資料庫的預設事務隔離級別就是�0�2READ_COMMITTED,Oracle、SQL Server、DB2等都有有自己的預設值。我認為 READ_COMMITTED 已經可以解決絕大多數問題了,其他的就具體情況具體分析吧。

若對其他資料庫的預設事務隔離級別不太清楚,可以使用以下代碼來獲取:

MySQL    
1 2 DatabaseMetaData meta = DBUtil.getDataSource().getConnection().getMetaData(); int defaultIsolation = meta.getDefaultTransactionIsolation();

 

提示:在 java.sql.Connection 類中可查看所有的隔離級別。

我們知道 JDBC 只是連接 Java 程式與資料庫的橋梁而已,那麼資料庫又是怎樣隔離事務的呢?其實它就是“鎖”這個東西。當插入數據時,就鎖定表,這叫“鎖表”;當更新數據時,就鎖定行,這叫“鎖行”。當然這個已經超出了我們今天討論的範圍,所以還是留點空間給我們的 DBA 同學吧,免得他沒啥好寫的了。

除了 JDBC 給我們提供的事務隔離級別這種解決方案以外,還有哪些解決方案可以完善事務管理功能呢?

不妨看看 Spring 的解決方案吧,其實它是對 JDBC 的一個補充或擴展。它提供了一個非常重要的功能,就是:事務傳播行為(Transaction Propagation Behavior)

確實夠牛逼的,Spring 一下子就提供了 7 種事務傳播行為,這 7 種行為一齣現,真的是亮瞎了我的狗眼!

  1. PROPAGATION_REQUIRED
  2. RROPAGATION_REQUIRES_NEW
  3. PROPAGATION_NESTED
  4. PROPAGATION_SUPPORTS
  5. PROPAGATION_NOT_SUPPORTED
  6. PROPAGATION_NEVER
  7. PROPAGATION_MANDATORY

看了�0�2Spring 參考手冊之後,更是暈了,這到底是在幹嘛?

首先要明確的是,事務是從哪裡來?傳播到哪裡去?答案是,從方法 A 傳播到方法 B。Spring 解決的只是方法之間的事務傳播,那情況就多了,比如:

  1. 方法 A 有事務,方法 B 也有事務。
  2. 方法 A 有事務,方法 B 沒有事務。
  3. 方法 A 沒有事務,方法 B 有事務。
  4. 方法 A 沒有事務,方法 B 也沒有事務。

這樣就是 4 種了,還有 3 種特殊情況。還是用我的 Style 給大家做一個分析吧:

假設事務從方法 A 傳播到方法 B,您需要面對方法 B,問自己一個問題:

方法 A 有事務嗎?

  1. 如果沒有,就新建一個事務;如果有,就加入當前事務。這就是�0�2PROPAGATION_REQUIRED,它也是 Spring 提供的預設事務傳播行為,適合絕大多數情況。
  2. 如果沒有,就新建一個事務;如果有,就將當前事務掛起。這就是�0�2RROPAGATION_REQUIRES_NEW,意思就是創建了一個新事務,它和原來的事務沒有任何關係了。
  3. 如果沒有,就新建一個事務;如果有,就在當前事務中嵌套其他事務。這就是�0�2PROPAGATION_NESTED,也就是傳說中的“嵌套事務”了,所嵌套的子事務與主事務之間是有關聯的(當主事務提交或回滾,子事務也會提交或回滾)。
  4. 如果沒有,就以非事務方式執行;如果有,就使用當前事務。這就是�0�2PROPAGATION_SUPPORTS,這種方式非常隨意,沒有就沒有,有就有,有點無所謂的態度,反正我是支持你的。
  5. 如果沒有,就以非事務方式執行;如果有,就將當前事務掛起。這就是�0�2PROPAGATION_NOT_SUPPORTED,這種方式非常強硬,沒有就沒有,有我也不支持你,把你掛起來,不鳥你。
  6. 如果沒有,就以非事務方式執行;如果有,就拋出異常。這就是�0�2PROPAGATION_NEVER,這種方式更猛,沒有就沒有,有了反而報錯,確實夠牛的,它說:我從不支持事務!
  7. 如果沒有,就拋出異常;如果有,就使用當前事務。這就是�0�2PROPAGATION_MANDATORY,這種方式可以說是牛逼中的牛逼了,沒有事務直接就報錯,確實夠狠的,它說:我必須要有事務!

看到我上面這段解釋,小伙伴們是否已經感受到,被打通任督二脈的感覺?多讀幾遍,體會一下,就是您自己的東西了。

需要註意的是�0�2PROPAGATION_NESTED,不要被它的名字所欺騙,Nested(嵌套),所以凡是在類似方法 A 調用方法 B 的時候,在方法 B 上使用了這種事務傳播行為,如果您真的那樣做了,那您就錯了。因為您錯誤地以為�0�2PROPAGATION_NESTED 就是為方法嵌套調用而準備的,其實預設的�0�2PROPAGATION_REQUIRED 就可以幫助您,做您想要做的事情了。

Spring 給我們帶來了事務傳播行為,這確實是一個非常強大而又實用的功能。除此以外,也提供了一些小的附加功能,比如:

  1. 事務超時(Transaction Timeout):為瞭解決事務時間太長,消耗太多的資源,所以故意給事務設置一個最大時常,如果超過了,就回滾事務。
  2. 只讀事務(Readonly Transaction:為了忽略那些不需要事務的方法,比如讀取數據,這樣可以有效地提高一些性能。

最後,推薦大家使用 Spring 的註解式事務配置,而放棄 XML 式事務配置。因為註解實在是太優雅了,當然這一切都取決於您自身的情況了。

在 Spring 配置文件中使用:

MySQL  
1 2 3 ... <tx:annotation-driven /> ...

 

在需要事務的方法上使用:

MySQL    
1 2 3 4 Transactional public void xxx() {     ... }

 

可在�0�2@Transactional 註解中設置:事務隔離級別、事務傳播行為、事務超時時間、是否只讀事務。


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

-Advertisement-
Play Games
更多相關文章
  • 目錄 1.序 2.題庫 3. Oracle 資料庫 資料庫本質是用電腦存儲數據的一種系統。它是位於 用戶 和系統 之間的一種管理軟體。 1.序 1.1 登錄SQLPLUS 1.2 創建一個自己的用戶(比如 vip/vip) 1.3 切換到用戶 1.4 使用 1.5 激活內置的測試賬號,這裡面有幾張 ...
  • 索引的類型 B-Tree索引 B-Tree 索引 通常意味著所有的值都是按順序存儲的,並且每一個葉子頁到根的距離相同。 B-Tree 索引 能夠加快訪問數據的速度,存儲引擎不再需要進行全表掃描來獲取需要的數據,取而代之的是從索引的根節點開始搜索。 B-Tree 索引 適用於全鍵值、鍵值範圍或鍵首碼查 ...
  • 在上一篇寫了介面調用解析返回的xml,並賦值到實體。這一篇主要介紹,如何保存實體數據。 一,xml樣例 二,表結構設計 1,批次號:各表之間用最外層批次號關聯。 2,主表:即把各層欄位全部存在一個表中。 三,實體設計 分為三層:CisReportRoot ,CisReportChild ,Repor ...
  • 記錄一下常用的語句,便於以後使用… create tablespace TABLESPACENAMEdatafile 'E:\Data\ORACLEDATA\XXX.dbf' size 200M autoextend on next 100M maxsize unlimited logging ex... ...
  • INSERT into user_info(version,create_user_count,create_pc_count) select version,create_user_count,create_pc_count from user_info;mysql蠕蟲複製,大量數據 。 ...
  • 使用PowerDesigner生成資料庫腳本時報 Constraint name uniqueness 錯誤: 雙擊每行錯誤,發現外鍵引用的名字有重覆的: 慣性去網上找解決辦法,找到的主要是兩個方法: 1.使用Automatic Correction 右鍵錯誤行,菜單中選擇Automatic Cor ...
  • [20180118]tstats的問題.txt--//關於使用tstats收集處理統計信息,可以看鏈接http://blog.itpub.net/267265/viewspace-1987839/TSTATS in a Nutshell P97The removal of time-sensitiv ...
  • /** * PowerDesigner裡面將表中name列值複製到comment列 * @see -----------------------------------------------------------------------------------------------------... ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...