當前位置:首頁 » 數據倉庫 » 資料庫樂觀鎖意義
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

資料庫樂觀鎖意義

發布時間: 2022-05-22 03:25:15

1. 悲觀鎖和樂觀鎖定義是什麼

悲觀鎖和樂觀鎖定義:

樂觀鎖:樂觀鎖在操作數據時非常樂觀,認為別人不會同時修改數據。因此樂觀鎖不會上鎖,只是在執行更新的時候判斷一下在此期間別人是否修改了數據:如果別人修改了數據則放棄操作,否則執行操作。

悲觀鎖:悲觀鎖在操作數據時比較悲觀,認為別人會同時修改數據。因此操作數據時直接把數據鎖住,直到操作完成後才會釋放鎖;上鎖期間其他人不能修改數據。

悲觀鎖實現方式

悲觀鎖的實現,往往依靠資料庫提供的鎖機制。在資料庫中,悲觀鎖的流程如下:

1.在對記錄進行修改之前,先嘗試為該記錄加上排它鎖(exclusive locking)。

2.如果加鎖失敗,說明該記錄正在被修改,那麼當前查詢可能要等待或者拋出異常。具體響應方式由開發者根據實際需要決定。

3.如果成功加鎖,那麼就可以對記錄做修改,事務完成後就會解鎖了。

4.期間如果有其他對該記錄做修改或加排它鎖的操作,都會等待解鎖或直接拋出異常。

2. 什麼是事務什麼是鎖

事務與鎖是不同的。事務具有ACID(原子性、一致性、隔離性和持久性),鎖是用於解決隔離性的一種機制。事務的隔離級別通過鎖的機制來實現。另外鎖有不同的粒度,同時事務也是有不同的隔離級別的(一般有四種:讀未提交Read uncommitted,
讀已提交Read committed,
可重復讀Repeatable read,
可串列化Serializable)。
在具體的程序設計中,開啟事務其實是要資料庫支持才行的,如果資料庫本身不支持事務,那麼仍然無法確保你在程序中使用的事務是有效的。
鎖可以分為樂觀鎖和悲觀鎖:
悲觀鎖:認為在修改資料庫數據的這段時間里存在著也想修改此數據的事務;
樂觀鎖:認為在短暫的時間里不會有事務來修改此資料庫的數據;
我們一般意義上講的鎖其實是指悲觀鎖,在數據處理過程中,將數據置於鎖定狀態(由資料庫實現)
如果開啟了事務,在事務沒提交之前,別人是無法修改該數據的;如果rollback,你在本次事務中的修改將撤消(不是別人修改的會沒有,因為別人此時無法修改)。當然,前提是你使用的資料庫支持事務。還有一個要注意的是,部分資料庫支持自定義sql鎖覆蓋事務隔離級別默認的鎖機制,如果使用了自定義的鎖,那就另當別論。
重點:一般事務使用的是悲觀鎖(具有排他性)

3. 資料庫高並發下樂觀鎖的原理

在高並發下,經常需要處理SELECT之後,在業務層處理邏輯,再執行UPDATE的情況。

若兩個連接並發查詢同一條數據,然後在執行一些邏輯判斷或業務操作後,執行UPDATE,可能出現與預期不相符的結果。

在不使用悲觀鎖與復雜SQL的前提下,可以使用樂觀鎖處理該問題,同時兼顧性能。


場景模擬:

假設一張表兩個欄位,一個id,一個use_count。
表裡存了100個id,每個id對應自己的use_count。

當id每使用一次,use_count要加1。當use_count大於1000時,這個id就不能在被使用了(換句話說 無法從資料庫中查出)。

在高並發情況下,會遇到一種問題:假設數據表中有一條記錄為:id=123456, use_count=999
A與B兩個連接並發查詢這個id=123456,都執行下列SQL:

SELECT*FROMtableWHEREid=123456anse_count<1000;

A先執行,得到id=123456的use_count是999,之後在程序里做了一些邏輯判斷或業務操作後執行SQL:

UPDATEtableSETuse_count+1WHEREid=123456;

在A做判斷且沒有update之前,B也執行了查詢SQL,發現use_count是999,之後它也會執行SQL:

UPDATEtableSETuse_count+1WHEREid=123456;

但是,事實上B不應該取得這個id,因為A已經是第1000個使用者。

處理步驟如下:

1、添加第3個欄位version,int類型,default值為0。version值每次update時作加1處理。

'0'NOTNULLAFTERuse_count;

2、SELECT時同時獲取version值(例如為3)。

SELECTuse_count,versionFROMtableWHEREid=123456ANDuse_count<1000;

3、UPDATE時檢查version值是否為第2步獲取到的值。

UPDATEtableSETversion=4,use_count=use_count+1WHEREid=123456ANDversion=3;

如果UPDATE的記錄數為1,則表示成功。
如果UPDATE的記錄數為0,則表示已經被其他連接UPDATE過了,需作異常處理。


參考地址:http://latrell.me/post-358.html

4. 樂觀鎖的介紹

相對悲觀鎖而言,樂觀鎖機制採取了更加寬松的加鎖機制。悲觀鎖大多數情況下依靠資料庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是資料庫 性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。相對悲觀鎖而言,樂觀鎖更傾向於開發運用!

5. 為何Redis用樂觀鎖,而MySQL資料庫卻沒有

簡單來說,Redis使用樂觀鎖,相對於悲觀鎖,在實現中更加簡單,在某些場景中的性能也更好。Redis作為一個輕量級的、快速的緩存引擎,而不是一個全功能的關系型資料庫,既沒有使用悲觀鎖的必要,也難以承受使用悲觀鎖的成本。
詳細來說,要深入到Redis和MySQL的事務處理機制。Redis關於事務的文檔見此:
Transactions(事務)
Redis對於事務只提供了非常有限的支持,其實更多地是試圖繞過問題。
首先,Redis對於同一事務中的一組操作,而不是立即執行,而是放入一個queue中,當執行到EXEC時,再一起執行。事務執行是全局獨占的,也就是同一時間只有一個事務被執行,中途不能被其它事務打斷。Redis用這種最簡單的、也是性能最差的方式避免了race
condition。
其次,在Redis的事務中,如果有一個或多個操作失敗,其它操作仍然會成功,也就是說它根本沒有回滾機制。
這種方式會帶來很多嚴重的問題,其中之一是,無法先讀取某個數值後再進行依賴這個值的操作,因為放在一個事務里會被在同一個瞬間執行,不放在同一個事務里又會導致race
condition。解決方法是使用WATCH,它會監視一個或多個變數,如果變數的值在調用WATCH以後和事務提交之前被別的事務修改過了,整個事務都會失敗。這類似於操作系統中的CAS(Compare
and
Set)。我不知道WATCH具體是怎麼實現的,但是我推測它監控了指定變數的版本號。
即使有了WATCH,Redis的事務也是受到嚴重限制的。第一,它沒有實現讀數據時的一致性,因為WATCH對於讀操作不起作用。第二,它不支持回滾。第三,在對同一變數存在大量並發寫操作時,性能會非常差,因為每次提交事務時,WATCH監控的變數都已經被修改了,導致事務將多次提交失敗。但是,Redis本來就是一個KV類型的緩存引擎,要處理的是大量讀少量寫的場景,對一致性也沒有要求。
MySQL就完全不一樣了,作為一個典型的關系型資料庫,它需要完整地實現ACID,所以Redis的方式是解決不了它的問題的。
MySQL中的MVCC機制(Oracle的也是),通過undo
日誌來獲取某個行記錄的歷史快照,從而實現了所謂的讀一致性。它的目的是讀取某個時間點上的歷史數據(而不是可能已經被修改了的數據),而不是避免悲觀鎖的使用。嚴格地說這不能稱之為樂觀鎖,因為它既不Compare當前版本和歷史版本,也不進行Set。事實上,在讀取記錄的歷史快照時,當前記錄有可能(由於並發的寫操作)已經被加上獨占鎖。
進一步的問題是:有沒有可能使用樂觀鎖來實現RDBMS中的寫一致性?有沒有可能使用樂觀鎖實現完整的ACID特性?
回答是可以。例如,MS
SQL
SERVER的Hekaton引擎通過一套基於時間戳的多版本管理系統,實現了不使用了悲觀鎖的ACID。
但是,這並不意味著樂觀鎖必然優於悲觀鎖。除了維護多版本的開銷以外,樂觀鎖無法避免的一個問題是,當多個寫操作試圖更新同一個對象時,只有第一個操作可以成功,其它的操作都會在Compare時失敗然後回滾,從而造成極大的性能問題。在這種情況下,樂觀鎖的性能會低於悲觀鎖。
目前的趨勢似乎是,大規模的分布式資料庫更傾向於使用樂觀鎖來達到所謂的external
consistency,因為基於傳統悲觀鎖的分布式鎖在集群大到一定程度以後(從幾百台擴展到成千上萬台時),性能開銷就大得無法接受了。Google的Spanner就是基於樂觀鎖。當然這完全是另外一個問題了。

6. 悲觀鎖和樂觀鎖的用處和區別

用處:保證數據安全,處理多用戶並發訪問

區別:

  1. 悲觀鎖,從數據開始更改時就將數據鎖住,知道更改完成才釋放。
    樂觀鎖,直到修改完成准備提交所做的的修改到資料庫的時候才會將數據鎖住。完成更改後釋放。

  2. 悲觀鎖會造成訪問資料庫時間較長,並發性不好,特別是長事務。樂觀鎖在現實中使用得較多,廠商較多採用。


7. 什麼是樂觀鎖

hibernate中兩種鎖機制: 悲觀鎖,樂觀鎖.
悲觀鎖:採用資料庫本身的鎖機制,for update或no wait
優點:處理並發徹底,並發處理比較好
缺點:當一個用戶鎖定記錄的時候,其它用戶都不能使用了,容易造成長時間的等待.

樂觀鎖:是Hibernate自己實現的,採用版本控制的方式實現處理並發.
1.添加version元素
2.聲明使用版本控制的方式實現樂觀鎖optimistic-lock="version"
<hibernate-mapping>
<class name="..." table="..." catalog="..." optimistic-lock="version"></class></hibernate-mapping>

8. mysql默認是樂觀鎖

樂觀鎖,悲觀鎖,這兩個概念你需要搞清楚才能更好的理解。
樂觀鎖:與悲觀鎖相對應,不是資料庫自帶的,需要自己去實現。
悲觀鎖:與樂觀鎖相對應,是資料庫自己實現了的。要用的時候,我們直接調用資料庫的相關語句就可以了。
悲觀鎖又涉及到其他兩個鎖概念,共享鎖和排他鎖。只有去理解和實際操作才能更好的理解這些具體的東西。
希望我的回答對你有所幫助

9. 樂觀鎖和悲觀鎖是mysql的概念嗎

關於mysql中的樂觀鎖和悲觀鎖面試的時候被問到的概率還是比較大的。
mysql的悲觀鎖:
其實理解起來非常簡單,當數據被外界修改持保守態度,包括自身系統當前的其他事務,以及來自外部系統的事務處理,因此,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制,但是也只有資料庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在自身系統中實現了加鎖機制,也無法保證外部系統不會修改數據。
來點實際的,當我們使用悲觀鎖的時候我們首先必須關閉mysql資料庫的自動提交屬性,因為mysql默認使用autocommit模式,也就是說,當你執行一個更新操作後,mysql會立刻將結果進行提交。
關閉命令為:set
autocommit=0;
悲觀鎖可以使用select…for
update實現,在執行的時候會鎖定數據,雖然會鎖定數據,但是不影響其他事務的普通查詢使用。此處說普通查詢就是平時我們用的:select
*
from
table
語句。在我們使用悲觀鎖的時候事務中的語句例如:
//開始事務
begin;/begin
work;/start
transaction;
(三選一)
//查詢信息
select
*
from
order
where
id=1
for
update;
//修改信息
update
order
set
name='names';
//提交事務
commit;/commit
work;(二選一)
此處的查詢語句for
update關鍵字,在事務中只有select
...
for
update
或lock
in
share
mode
同一條數據時會等待其它事務結束後才執行,一般的select查詢則不受影響。
執行事務時關鍵字select…for
update會鎖定數據,防止其他事務更改數據。但是鎖定數據也是有規則的。
查詢條件與鎖定范圍:
1、具體的主鍵值為查詢條件
比如查詢條件為主鍵id=1等等,如果此條數據存在,則鎖定當前行數據,如果不存在,則不鎖定。
2、不具體的主鍵值為查詢條件
比如查詢條件為主鍵id>1等等,此時會鎖定整張數據表。
3、查詢條件中無主鍵
會鎖定整張數據表。
4、如果查詢條件中使用了索引為查詢條件
明確指定索引並且查到,則鎖定整條數據。如果找不到指定索引數據,則不加鎖。
悲觀鎖的確保了數據的安全性,在數據被操作的時候鎖定數據不被訪問,但是這樣會帶來很大的性能問題。因此悲觀鎖在實際開發中使用是相對比較少的。
mysql的樂觀鎖:
相對悲觀鎖而言,樂觀鎖假設數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會對數據的沖突與否進行檢測,如果發現沖突,則讓返回用戶錯誤的信息,讓用戶決定如何去做。
一般來說,實現樂觀鎖的方法是在數據表中增加一個version欄位,每當數據更新的時候這個欄位執行加1操作。這樣當數據更改的時候,另外一個事務訪問此條數據進行更改的話就會操作失敗,從而避免了並發操作錯誤。當然,還可以將version欄位改為時間戳,不過原理都是一樣的。
例如有表student,欄位:
id,name,version
1
a
1
當事務一進行更新操作:update
student
set
name='ygz'
where
id
=
#{id}
and
version
=
#{version};
此時操作完後數據會變為id
=
1,name
=
ygz,version
=
2,當另外一個事務二同樣執行更新操作的時候,卻發現version
!=
1,此時事務二就會操作失敗,從而保證了數據的正確性。
悲觀鎖和樂觀鎖都是要根據具體業務來選擇使用,本文僅作簡單介紹。

10. 樂觀鎖的優點

從上面的例子可以看出,樂觀鎖機制避免了長事務中的資料庫加鎖開銷(操作員 A和操作員 B 操作過程中,都沒有對資料庫數據加鎖),大大提升了大並發量下的系統整體性能表現。