mysql的ACID的理解

這是在網上copy下來的ACID的概念,能夠直接跳過看後面:java

一、原子性(Atomicity):事務開始後全部操做,要麼所有作完,要麼所有不作,不可能停滯在中間環節。事務執行過程當中出錯,會回滾到事務開始前的狀態,全部的操做就像沒有發生同樣。也就是說事務是一個不可分割的總體,就像化學中學過的原子,是物質構成的基本單位。mysql

二、一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。好比A向B轉帳,不可能A扣了錢,B卻沒收到。
三、隔離性(Isolation):同一時間,只容許一個事務請求同一數據,不一樣的事務之間彼此沒有任何干擾。好比A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉帳。算法

四、持久性(Durability):事務完成後,事務對數據庫的全部更新將被保存到數據庫,不能回滾。sql

 

其中,原子性和持久性的概念比較好理解。可是最近發現總是把一致性和隔離性混淆。數據庫

我的理解,隔離性主要是針對讀操做的。在不一樣事務之間,讀操做隔離。好比另外一個事務對數據修改後,會不會影響當前事務的讀操做,要不要讀到更新後的數據。編程

一致性,主要強調的是數據的更新是否是「正確」,即,是否是符合咱們的預期,這個和讀操做應該是要分開看待的,這裏應該只強調寫操做。緩存

 

形成我對這倆個概念的混淆的緣由是,在java的併發編程中,咱們關注的彷佛只有一致性,沒據說過java併發編程中有什麼隔離性。形成這個的緣由是,咱們使用鎖,或者volition來保證數據的讀取是「正確」的,這種「正確」性的保證是經過「排他鎖「(這裏加引號是由於嚴格來講,和排它鎖可能會有輕微的區別,好比cpu的緩存鎖,緩存失效機制,可是效果上仍是有排他的效果)來保證的。這種鎖機制,是比mysql的MVCC,或者讀鎖更加嚴格的,也就是說在java併發編程中本質上是沒有讀鎖(或者樂觀鎖)這種概念的,就算是ReentrantReadWriteLock ,也是一種對mysql的讀寫鎖的仿製,在java的底層是不存在這種東西的。併發

而mysql中所強調的一致性,就和java併發編程中的一致性基本是一致的了,都是經過排他鎖來保證的,因此在對倆者進行編程時,他們倆者的思路是互通的,是能夠相互借鑑的。事務

mysql爲了增長併發量,引入了樂觀鎖,MVCC這種概念,可是也帶來了隔離的問題,即由於沒有排它的強制性保證,就會出現讀和寫併發的場景,那麼就須要考慮,在倆者併發的場景下,讀操做到底該作什麼樣約束的問題。相反,在java併發編程中,能夠理解爲,在排它的保證下,是不會出現讀和寫併發的存在的場景的,也就不會有隔離性的問題。(你們能夠想一個java中的lock,還有無鎖算法中依賴的CAS底層也會有lock前綴的指令)。ci

 

最後,當認識到這些問題的時候,咱們在寫sql的時候有什麼借鑑的意義呢?

我的意見:

1.把沒必要要引入的隔離性問題,也就是讀操做,能夠省掉的就省掉。好比 咱們要併發的對數據庫中一條記錄的值進行加一操做。也許能夠先select出它的值,而後在java程序中+1,而後再update回去,爲了防止併發帶來的一致性問題,能夠在update的where條件中帶上變量的原值。 可是,若是直接update ... set variable= variable +1 這樣呢,這樣的話,就把讀操做,也就是隔離性的問題消除了,所有都轉化成了寫操做,也就是一致性的問題了,而mysql使用排他策略來進行寫,在這種場景下是能夠保證一致性的。

2.咱們在考慮要不要加事務,要什麼樣的隔離級別的時候,思路就會更加的清晰。在考慮隔離性的時候,咱們首先就知道它強調的是讀的操做,那首先就專心考慮咱們對讀的要求,而不會被其餘操做所幹擾。

其次,咱們須要考慮咱們對讀回的值作了什麼計算,而後是怎樣把計算的結果又更新到數據庫中的。那麼,因爲讀獲得的數據不必定是」正確的「,咱們的寫操做是否須要加一致性的校驗(好比在where條件中加上預期的原值)。

舉個例子:仍是剛剛的對一個記錄併發的加一,假設咱們使用先select,而後update的方法,並且咱們一個操做單元是多條記錄。

首先,因爲咱們的操做單元是多條記錄,因此咱們須要原子性,即這批數據要麼所有成功,要麼所有失敗,因此咱們對這屢次的select,update操做加上了事務。

而後,咱們的select應該使用什麼樣的隔離級別呢?

首先考慮下可重複讀,在這種隔離級別下,頗有可能讀到」不正確「的數據,即別的事務提交了對這個值的修改,可是咱們在當前事務中讀到的仍然是老的數據,那麼致使計算出來的結果確定是」不正確「的。

而後咱們考慮下提交讀,那麼在這種隔離級別下,不會出現剛剛說的問題了,可是,因爲併發的問題,在咱們讀完後,可能另外一個事務提交了對這條記錄的修改。這又形成了當前事務中計算結果的錯誤。

最後,是讀未提交,在這種級別下,面臨的就是另一個事務在更新後,而後又回滾所形成的問題了。

那麼能夠發現,這三種隔離級別都無法知足咱們的要求,因此,就會發現,原來咱們對隔離性其實沒什麼必須的要求,咱們這裏須要的,只是數據一致性的要求。爲何我沒有說串行化的隔離級別呢,由於這種隔離級別下,全部的操做都是排他的,是不存在隔離性的問題的。

上面舉的這倆個例子都很簡單,咱們實際的場景也許會比這複雜的多,可是,若是理解了上面說的隔離性和一致性到底指的是什麼,我以爲在面對複雜場景時,是能夠縷出一條很好的解決思路的。

相關文章
相關標籤/搜索