樂觀鎖是邏輯概念上的鎖,不是數據庫自帶的,須要咱們本身去實現。樂觀鎖是指操做數據庫時(更新操做),想法很樂觀,認爲此次的操做不會致使衝突,在操做數據時,並不進行任何其餘的特殊處理(也就是不加鎖),而在進行更新後,再去判斷是否有衝突了。java
一般實現是這樣的:在表中的數據進行操做時(更新),先給數據表加一個版本(version)字段,每操做一次,將那條記錄的版本號加1。也就是先查詢出那條記錄,獲取出version字段,若是要對那條記錄進行操做(更新),則先判斷此刻version的值是否與剛剛查詢出來時的version的值相等,若是相等,則說明這段期間,沒有其餘程序對其進行操做,則能夠執行更新,將version字段的值加1;若是更新時發現此刻的version值與剛剛獲取出來的version的值不相等,則說明這段期間已經有其餘程序對其進行操做了,則不進行更新操做。mysql
舉例:sql
下單操做包括3步驟:數據庫
1.查詢出商品信息spa
select (status,version) from t_goods where id=#{id}
2.根據商品信息生成訂單code
3.修改商品status爲2對象
update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};
與樂觀鎖相對應的就是悲觀鎖了。悲觀鎖就是在操做數據時,默認此操做會出現數據衝突,因此在進行每次操做時都要經過獲取鎖才能進行對相同數據的操做,這點跟java中的synchronized很類似,因此悲觀鎖須要耗費較多的時間。悲觀鎖的實現,依靠數據庫提供的鎖機制,使用的時候直接調用數據庫的相關語句就能夠了。blog
數據庫上的操做能夠概括爲兩種:讀和寫。多個事務同時讀取一個對象的時候,是不會有衝突的。同時讀和寫,或者同時寫纔會產生衝突。事務
MyIsam引擎會爲查詢和更新等操做自動添加表級鎖,所以它的狀況比較簡單。InnoDB引擎狀況比較複雜,它一般會定義兩種鎖:共享鎖和排它鎖。文檔
共享鎖(Shared Lock,也叫S鎖)表示對數據進行讀操做,加鎖後其餘事務能夠讀,但不能寫。多個事務能夠同時爲一個對象加共享鎖。
SELECT ... LOCK IN SHARE MODE走的是IS鎖(意向共享鎖),即在符合條件的rows上都加了共享鎖,這樣的話,其餘人能夠讀取這些記錄,也能夠繼續添加IS鎖,可是沒法修改這些記錄直到你這個加鎖的過程執行完成(完成的狀況有:事務的提交,事務的回滾,不然直接鎖等待超時)。
SELECT ... LOCK IN SHARE MODE的應用場景適合於兩張表存在關係時的寫操做,拿mysql官方文檔的例子來講,一個表是child表,一個是parent表,假設child表的某一列child_id映射到parent表的c_child_id列,那麼從業務角度講,此時我直接insert一條child_id=100記錄到child表是存在風險的,由於剛insert的時候可能在parent表裏刪除了這條c_child_id=100的記錄,那麼業務數據就存在不一致的風險。正確的方法是再插入時執行select * from parent where c_child_id=100 lock in share mode,鎖定了parent表的這條記錄,而後執行insert into child(child_id) values (100)就不會存在這種問題了。
排他鎖(Exclusive Lock,也叫X鎖)也叫寫鎖。加鎖後,其餘事務不能讀取,也不能寫。
若是一個事務對對象加了排他鎖,其餘事務就不能再給它加任何鎖了。
產生排他鎖的sql: SELECT ... FOR UPDATE
共享鎖適用於兩張表存在業務關係時的一致性要求,排它鎖適用於操做同一張表時的一致性要求。