高併發情況下使用樂觀鎖保證系統穩定性和冪等性

加粗樣式## 高併發情況下使用樂觀鎖保證系統穩定性和冪等性

今天我們會介紹在高併發的情況下,保證系統穩定性和冪等性的同時如何最大化系統效率

我們可以先想想這個場景,現在我們在維護一個學生管理系統,系統內的數據庫儲存了所有學生的信息。這一天新來了一位同學小明,學生管理員小紅和小剛把小明的個人信息插入到數據庫中,碰巧小紅和小剛同時點擊了提交按鈕。

在這裏插入圖片描述
這樣一來數據庫中會有兩條小明的信息,不符合預期。

解決方案

方案一

第一種解決方案就是向數據庫中加入唯一索引

CREATE UNIQUE INDEX student_id_unique ON Students(studentId);

這樣一來有效的解決了上訴問題,當第二條數據被插入庫中時會被拒絕。

可是請求不爲Insert而是Update呢?單單加入唯一索引並不能保證冪等性。

方案二

我們可以利用InnerDB自帶的數據庫隔離機制來解決問題,隔離級別有Read Uncommitted, Read Committed, Read Repeatable, 和 Serializable。這四個級別可以逐個解決髒寫、髒讀、不可重複讀、幻讀這幾類問題。有關此類詳細說明的文章網上有很多,這裏就不一一介紹了。

在這裏只有Serializable可以幫助我們解決問題,通過序列化強制隔離不同事物,讓事物只能一個一個的去運行。

這個方案雖然解決了關鍵問題,可是讓整個系統強依賴於數據庫的隔離級別會導致整個系統過於脆弱,並且會導致系統不具備良好的併發性。

方案三

第三種方案就是使用樂觀鎖。現在已經有很多成熟的樂觀鎖方案,如CAS,版本號等等,這次我們拿版本號舉例子。

我們可以向表中額外加一列屬性,即爲版本號。

老表:

studentID, name

新表:

studentID,name,version

version從1開始增加,以下爲新方案的SQL更新語句。

SELECT version FROM Student WHERE studentID = '1234567';
// 得到1
UPDATE Student SET name = 'new name', version = 2 WHERE studentID = '1234567' AND version = 1;
//僅僅在版本號爲一的時候語句纔會生效

這是一個經典的版本號樂觀鎖的使用方法,這樣一來當小紅和小剛同時更新數據時,假設小紅先更新成功,版本號會從1變爲2,小剛的update請求就會被拒絕了(因爲版本號已經變了)。我們還可以在後端增加回滾控制,當請求被拒絕時可以放棄或者重試。

這樣一來事物就可以併發運行了,我們再將唯一索引加入到表中,便可以有效地解決所有問題啦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章