注意事項

有大量資料的資料庫,要更改定序時,務必下班再做or確認不會卡到別人的事情

隔離級別

參考資料:(https://openhome.cc/Gossip/HibernateGossip/IsolationLevel.html)

參考資料:(https://blog.csdn.net/baidu_37107022/article/details/77481670)

參考資料:(https://read01.com/zh-tw/P2L3na.html#.XM_ICOgzaUk)

隔離性是交易的保證之一,表示交易與交易之間不互相干擾,好像同時間就只有自己的交易存在一樣,隔離性保證的基本方式是在資料庫層面,對資料庫或相關欄位鎖定,在同一時間內只允許一個交易進行更新或讀取。

資料庫有可能發生的問題:

  1. 更新遺失(lost update)

  2. 二次更新遺失(second lost update)

  3. 髒讀(dirty read)

  4. 無法重複的讀取(unrepeatable read)

  5. 幻讀(phantom read)

隔離級別總共有四種

  1. Read uncommitted

  2. Read committed (SQL Server、Oracle Default)

  3. Repeatable read (MySQL Default)

  4. Serializable

隔離交易的基本方式是鎖定資料庫,但完全的鎖定資料庫實務上並不會這麼作,因為完全的鎖定資料庫將導致嚴重的效能問題,因此實務上會根據資料讀寫更新的頻繁性,設定不同的交易隔離層級(transaction isolation level):

Read uncommitted

當隔離級別設定為 Read uncommitted 時,至少可避免更新遺失的問題。當對同一個欄位資料做更新的時候,第二筆要先等第一筆事務完成。 在 commit 以前的修改 也會被讀取到,這會導致人看到過渡性 or 錯誤的資料。

比如有一項事務,有一筆資料一開始是 A,會先被改成B,最後改成C,接著執行commit。倘若在執行事務時,該筆資料被查詢,有可能就會把B送出去。而這是不應該的,要馬看到 A (原本的),要馬看到C (執行完成的),中間的不穩定、過渡性資料不應該被查詢、造成誤導、錯誤,這就叫做髒讀。

Read committed

當隔離級別設定為 Read committed 時,可以避免髒讀的問題,交易讀取的資料,至少要是已經確認的資料

基本作法是,讀取的交易不會阻止其他交易,但是一個未確認的更新 會阻止其他所有的交易,但這就會因此影響效能。 有一種作法是 交易正在更新,尚未確定前 都先操作暫存表格。

但還是會有 不可重複讀取 的問題。

不可重複讀取 的概念是:有一項A事務 它先查詢餘額有2000元,確認有足夠的餘額後,先去做其他事情,在最後準備扣除餘額,去做付款的動作。可是在執行完成之前,被另外一項事務B搶先了,直接被超車,把餘額扣掉,這樣A事務執行到最後,就會發生錯誤,提示餘額不足。這就叫做 不可重複讀。

Repeatable read

當隔離級別設定為 Repeatable read 時,可以避免不可重複讀取的問題,他保證 同一交易內兩次讀取的資料必須相同

基本作法是 讀取交易不會阻止其他的讀取,但是會阻止其他寫入的交易,但這影響效能較大。

但還是會有 幻讀 的問題。

幻讀 的概念是:在同一個事務,有兩個查詢事務,因為兩次查詢之間,被新增、刪除了資料,導致筆數不一致。 就好像產生幻覺。

Serializable

當隔離級別設定為 Serializable 時,可以避免 幻讀 的問題,這是最嚴格的隔離層級,只要有資料不一致的疑慮,交易必須可以循序的一個一個來。(也是因此被叫做 Serializable)

基本作法是 A交易讀取時,B交易若要更新,必須循序。如果A交易需要更新,不論B交易是讀取還是更新,都必須循序。

因為 read uncommited 出錯的機率太大,而 serializable 又嚴重傷害系統效能,所以大部分的應用程式都會選用 read commited 和 repeatable read 這兩個層級。

悲觀鎖和樂觀鎖比較

參考資料:(https://juejin.im/post/6844903742161027079)

悲觀鎖適合寫多讀少的場景。

因為在使用的時候該線程會獨占這個資源,在本文的例子來說就是某個id的文章,如果有大量的評論操作的時候,就適合用悲觀鎖,否則用戶只是瀏覽文章而沒什麼評論的話,用悲觀鎖就會經常加鎖,增加了加鎖解鎖的資源消耗。

樂觀鎖適合寫少讀多的場景。

由於樂觀鎖在發生衝突的時候會回滾或者重試,如果寫的請求量很大的話,就經常發生衝突,經常的回滾和重試,這樣對系統資源消耗也是非常大。

所以悲觀鎖和樂觀鎖沒有絕對的好壞,必須結合具體的業務情況來決定使用哪一種方式。 另外在阿里巴巴開發手冊裡也有提到:

如果每次訪問衝突概率小於 20%,推薦使用樂觀鎖,否則使用悲觀鎖。樂觀鎖的重試次數不得小於 3 次。

阿里巴巴建議以沖突概率20%這個數值作為分界線來決定使用樂觀鎖和悲觀鎖,雖然說這個數值不是絕對的,但是作為阿里巴巴各個大佬總結出來的也是一個很好的參考。

Last updated