一、為什麼需要鎖(併發控制)
在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。
典型的衝突有:
為了解決這些併發帶來的問題,我們需要引入併發控制機制。
二、併發控制機制
三、樂觀鎖
樂觀鎖介紹:
樂觀鎖相對於悲觀鎖而言,樂觀鎖假設資料一般情況下不會發生衝突,所以在資料提交更新時候,才會正式的對資料的衝突與否進行檢測,如果發現衝突了,則給使用者返回錯誤資訊,讓使用者決定如何去做,樂觀鎖主要有兩種實現方式:
使用資料版本記錄機制實現:何謂資料版本,即為資料增加乙個版本標識,一般是通過為資料庫表增加乙個數字型別的「version」字段實現,當讀取資料時,將version欄位的值一同讀出,資料每更新一次,對此version的值+1,當我們提交更新的時候,判斷資料庫表對應記錄的當前版本資訊與第一次取出時的版本資訊是否一致,一致則更新,否則認為是過期資料。
如上圖所示,如果更新操作順序執行,則資料的版本(version)依次遞增,不會產生衝突。但是如果發生有不同的業務操作對同一版本的資料進行修改,那麼,先提交的操作(圖中b)會把資料version更新為2,當a在b之後提交更新時發現資料的version已經被修改了,那麼a的更新操作會失敗。
給出查詢和更新操作的執行sql
查詢: select (status,status,version) from t_goods where id=#
更新:update t_goods set status=2,version=version+1 where id=# and version=#;
那麼我們在更新的時候需要傳入的引數要加上「資料版本」這個字段。
2.樂觀鎖定的第二種實現方式和第一種差不多,同樣是在需要樂觀鎖控制的table中增加乙個字段,名稱無所謂,字段型別使用時間戳(timestamp), 和上面的version類似,也是在更新提交的時候檢查當前資料庫中資料的時間戳和自己更新前取到的時間戳進行對比,如果一致則ok,否則就是版本衝突。
四、悲觀鎖應用
需要使用資料庫的鎖機制,例如
select * from
需要使用資料庫的鎖機制,比如sql server 的tablockx(排它表鎖) 此選項被選中時,sql server 將在整個表上置排它鎖直至該命令或事務結束。這將防止其他程序讀取或修改表中的資料。
begin tran select top 1 @trainno=t_no from train_ticket with (updlock) where s_flag=0 update train_ticket set t_name=user, t_time=getdate(), s_flag=1 where t_no=@trainno commit
我們在查詢的時候使用了with (updlock)選項,在查詢記錄的時候我們就對記錄加上了更新鎖,表示我們即將對此記錄進行更新. 注意更新鎖和共享鎖是不衝突的,也就是其他使用者還可以查詢此表的內容,但是和更新鎖和排它鎖是衝突的.所以其他的更新使用者就會阻塞.
五、結論
在實際生產環境中,如果併發量不大且不允許髒讀,可以使用悲觀鎖解決併發問題,但如果系統的併發非常大的話,悲觀鎖會帶來非常大的效能問題,所以我們就要選擇樂觀鎖定的方式。
悲觀鎖樂觀鎖
1 悲觀鎖,正如其名,它指的是對資料被外界 包括本系統當前的其他事務,以及來自外部系統的事務處理 修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制 也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無...
樂觀鎖 悲觀鎖
悲觀鎖 pessimistic lock 顧名思義,就是很悲觀,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會block直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。樂觀鎖 optim...
樂觀鎖 悲觀鎖
樂觀鎖 悲觀鎖 悲觀鎖 pessimistic locking 悲觀鎖,正如其名,它指的是對資料被外界 包括本系統當前的其他事務,以及來自外部系統的事務處理 修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制 也只有資料庫層提供的鎖機制才能真正保...