悲觀鎖(Pessimistic Locking):
悲觀鎖,正如其名,它指的是對資料被外界(包括本系統目前的其他事務,以及來自 外部系統的事務處理)修改持保守态度,是以,在整個資料處理過程中,将資料處于鎖定狀态。
悲觀鎖的實作,往往依靠資料庫提供的鎖機制(也隻有資料庫層提供的鎖機制才能 真正保證資料通路的排他性,否則,即使在本系統中實作了加鎖機制,也無法保證外部系 統不會修改資料)。
通俗了解:一段資料在被A以悲觀鎖的形式通路(select * from card_record where status ="03' for update),那麼在這個通路沒有commit或者事務結束之前,這些 status ="03'的資料是無法被修改的。這條 sql 語句鎖定了 card_record 表中所有符合檢索條件( status ="03' )的記錄。本次事務送出之前(事務送出時會釋放事務過程中的鎖),外界無法修改這些記錄。 需要注意的是for update要放到mysql的事務中,即begin和commit中,否則不起作用。
悲觀鎖有兩種:讀鎖和寫鎖。上面的操作屬于寫鎖的操作,A上了鎖,那麼别人就不可以再上鎖了,有鎖的人可以對資料進行讀寫操作。而讀鎖相當于共享鎖,開啟事務後,A上了共享鎖,那麼其他人也可以上共享鎖。大家都可以讀這些資料,但是都不能修改。
悲觀的了解,别人在我讀寫資料的時候會進行更改,那麼我就上鎖,在我讀寫資料的時候不允許别人更改我正在操作的資料。
樂觀鎖(Optimistic Locking):
由于悲觀鎖在頻繁依靠資料庫的鎖機制實作,以保證操作最大程度的獨占性。但随之而來的就是資料庫性能的大量開銷。而樂觀鎖機制避免了長事務中的資料庫加鎖開銷,大大提升了大并發量下的系統整體性能表現。
樂觀鎖,大多是基于資料版本(Version )記錄機制實作。何謂資料版本?即為資料增加一個版本辨別,在基于資料庫表的版本解決方案中,一般是通過為資料庫表增加一個 “version” 字段來 實作。 讀取出資料時,将此版本号一同讀出,之後更新時,對此版本号加一。此時,将送出資料的版本資料與資料庫表對應記錄的目前版本資訊進行比對,如果送出的資料 版本号大于資料庫表目前版本号,則予以更新,否則認為是過期資料。
通俗的講,A和B都在對一個版本為1的資料進行修改,在事務送出之前,這段資料的版本一直是1,那麼下次送出的人會把這段資料的版本變為2。如果A在B之前送出了,那麼這段資料的版本變為2,之後B送出了資料,由于B拿到資料的時候版本是1,那麼加一後,預估版本也是2,但是送出完發現,現在的版本已經是2了,是以B的修改和送出是無效的。
需要注意的是,樂觀鎖機制往往基于系統中的資料存儲邏輯,是以也具備一定的局限性,如在上例中,由于樂觀鎖機制是在我們的系統中實作,來自外部系統的使用者對資料的操作不受我們系統的控制,是以可能會造成髒資料被更新到資料庫中。在 系統設計階段,我們應該充分考慮到這些情況出現的可能性,并進行相應調整(如将樂觀鎖政策在資料庫存儲過程中實作,對外隻開放基于此存儲過程的資料更新途 徑,而不是将資料庫表直接對外公開)。
樂觀的了解,在我讀寫資料的時候,沒人對這段資料進行更改,是以可以随意更改資料,隻是commit的時候可能會出現版本問題。
悲觀鎖,前提是,一定會有并發搶占資源,強行獨占資源,在整個資料處理過程中,将資料處于鎖定狀态。
樂觀鎖,前提是,不會發生并發搶占資源,隻有在送出操作的時候檢查是否違反資料完整性。隻能防止髒讀後資料的送出,不能解決髒讀。