一篇文章看懂事務的一致性

1、前言java

    事務一直以來是一個玄之又玄的東西,很是難以理解。難以理解倒不是由於事務自己有多難,而是事務這個概念被各類刻意包裝,以致於讓人暈頭轉向,摸不着頭腦。例如各類抽象的概念,一致性、持久性、原子性、持久性、讀未提交、讀已提交、可重複讀、序列化,Spring也抽象了事務的傳播屬性,數據庫自己又有各類鎖,因而咱們就暈頭了。今天咱們就來扒一扒事務,看看事務華麗外衣下的本質。本篇博客結合沈詢的分享,加上本身的一些總結。數據庫

2、事務要解的最終問題——「一致性」安全

    一致性是一個名詞,其實這裏實際上應該當成一個動詞來理解,多個參與者達成一致,達成了共識,相互之間不扯皮。這樣說可能比較抽象,舉個生活中的例子。併發

     一天,老王和老王老婆,同時去銀行取錢,老王查了銀行卡帳號有1w塊錢,因而取了出來,假設老王老婆和老王同時查詢,也看到有1w塊錢,因而點擊取款,最後發現沒錢可取了,因而要扯皮了,這就不一致了。性能

    用一句通俗的話來描述事務的一致性:全部事務的參與方,眼所見,即是心所得。上面的例子中,老王老婆看到了卡上有1w,卻無法取,因而就要扯皮了。這就是嚴苛的一致性所定義的內容。.net

    下面咱們來具體分析一下上面的例子。線程

    首先引出事務單位的概念,事務單元就是完成一個具體的業務的最小單元,上面的例子中包含兩個事務單元。按照正常的時間線,要想不扯皮,應該看到以下執行順序。3d

    

        可是扯皮的事情發生了,兩個事務單元並行了,因而出現以下的執行順序。事務單元二左移,與事務單元一併行。code

    

    上面的場景似曾相識,其實就是和線程安全所描述的內容一摸同樣,《一篇文章看懂Java併發和線程安全》,要想不扯皮,必須讓訪問的共享資源互斥,用Java代碼能夠描述成以下的代碼:blog

public class Consistency {

	public static void main(String[] args) {
		ReentrantLock lock = new ReentrantLock();
		lock.lock();
		try {
			int balance = query();// 查詢餘額
			if (balance > 0) {
				drawingOutCash();// 取出現金
			}
		} catch (Exception e) {

		} finally {
			lock.unlock();
		}
	}
}

   要想強一致,全部的事務單元串行着執行,這就是事務隔離級別中的SERIALIZABLE,因而就引出了事務的隔離級別。

3、事務的隔離級別

    強一致,必須讓全部事物單元串行執行,這即是隔離級別中的SERIALIZABLE(序列化),可是這樣系統的性能是可想而知的,幾乎不可用,因而須要放寬對鎖的要求,因此出現了其餘的隔離級別。事務的隔離級別是以性能爲由對一致性的破壞,它的出現是爲了破壞一致性,而不是維持一致性。

    事務單元與事務單元的關係只有四種:讀讀、讀寫、寫讀、寫寫

    SERIALIZABLE(序列化)

    

    要想進一步提高性能,因而出現了讀寫鎖,這裏就出現了兩種隔離級別:REPEATABLE_READ(可重複讀)和READ_COMMITED(讀已提交)

    REPEATABLE_READ(可重複讀):

    讀鎖不能被升級爲寫鎖,那麼對共享資源的寫,就進不來,這樣「讀讀」是可並行的,這樣會出現幻讀,由於在這個級別,表是不會被看作是共享資源的,因此能夠insert

    

    READ_COMMITED(讀已提交):

    讀鎖能夠被升級爲寫鎖,那麼當對共享資源正在讀時,能夠被寫請求升級爲寫鎖,那麼這樣「讀讀」、「讀寫」能夠並行,因而出現了幻讀、不可重複讀等等現象

    

    READ_UNCOMMITTED

    只加寫鎖,讀不用申請鎖,這樣「讀讀」、「讀寫」、「寫讀」均可以並行,但「寫寫」還不能並行,因而全部的寫都是串行,因而就有了髒讀、不可重複讀、幻讀等等。

    

    這就是事務隔離級別的真相,事務隔離級別越低,並行度越好,一致性越低。

4、一句話總結

    事務的一致性和線程安全所面對的問題如出一轍,要想維持一致性,須要保證兩點:共享變量的可見性、臨界區代碼訪問的順序性。

 

快樂源於分享。

此博客乃做者原創, 轉載請註明出處

相關文章
相關標籤/搜索