資料庫悲觀鎖和樂觀鎖
A. Oracle資料庫默認使用的是樂觀鎖還是悲觀鎖
Oracle資料庫默認使用的是樂觀鎖。任何一個以UPDATE…SET開始並且不是以SELECT…FOR UPDATE進行操作的命令就是一個樂觀鎖的例子。
B. 樂觀鎖和悲觀鎖是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,此時事務二就會操作失敗,從而保證了數據的正確性。
悲觀鎖和樂觀鎖都是要根據具體業務來選擇使用,本文僅作簡單介紹。
C. mysql什麼是悲觀鎖和樂觀鎖
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型資料庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像資料庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
D. Oracle創建悲觀鎖和樂觀鎖
為了得到最大的性能,一般資料庫都有並發機制,不過帶來的問題就是數據訪問的沖突。為了解決這個問題,大多數資料庫用的方法就是數據的鎖定。
數據的鎖定分為兩種方法,第一種叫做悲觀鎖,第二種叫做樂觀鎖。什麼叫悲觀鎖呢,悲觀鎖顧名思義,就是對數據的沖突採取一種悲觀的態度,也就是說假設數據肯定會沖突,所以在數據開始讀取的時候就把數據鎖定住。而樂觀鎖就是認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則讓用戶返回錯誤的信息,讓用戶決定如何去做。
先從悲觀鎖開始說。在SqlServer等其餘很多資料庫中,數據的鎖定通常採用頁級鎖的方式,也就是說對一張表內的數據是一種串列化的更新插入機制,在任何時間同一張表只會插1條數據,別的想插入的數據要等到這一條數據插完以後才能依次插入。帶來的後果就是性能的降低,在多用戶並發訪問的時候,當對一張表進行頻繁操作時,會發現響應效率很低,資料庫經常處於一種假死狀態。而Oracle用的是行級鎖,只是對想鎖定的數據才進行鎖定,其餘的數據不相干,所以在對Oracle表中並發插數據的時候,基本上不會有任何影響。
註:對於悲觀鎖是針對並發的可能性比較大,而一般在我們的應用中用樂觀鎖足以。
Oracle的悲觀鎖需要利用一條現有的連接,分成兩種方式,從SQL語句的區別來看,就是一種是for update,一種是for update nowait的形式。比如我們看一個例子。首先建立測試用的資料庫表。
CREATE TABLE TEST(ID,NAME,LOCATION,VALUE,CONSTRAINT test_pk PRIMARY KEY(ID))AS SELECT deptno, dname, loc, 1 FROM scott.dept
這里我們利用了Oracle的Sample的scott用戶的表,把數據到我們的test表中。首先我們看一下for update鎖定方式。首先我們執行如下的select for update語句。
select * from test where id = 10 for update
通過這條檢索語句鎖定以後,再開另外一個sql*plus窗口進行操作,再把上面這條sql語句執行一便,你會發現sqlplus好像死在那裡了,好像檢索不到數據的樣子,但是也不返回任何結果,就屬於卡在那裡的感覺。這個時候是什麼原因呢,就是一開始的第一個Session中的select for update語句把數據鎖定住了。由於這里鎖定的機制是wait的狀態(只要不表示nowait那就是wait),所以第二個Session(也就是卡住的那個sql*plus)中當前這個檢索就處於等待狀態。當第一個session最後commit或者rollback之後,第二個session中的檢索結果就是自動跳出來,並且也把數據鎖定住。不過如果你第二個session中你的檢索語句如下所示。
select * from test where id = 10
也就是沒有for update這種鎖定數據的語句的話,就不會造成阻塞了。另外一種情況,就是當資料庫數據被鎖定的時候,也就是執行剛才for update那條sql以後,我們在另外一個session中執行for update nowait後又是什麼樣呢。比如如下的sql語句。 由於這條語句中是制定採用nowait方式來進行檢索,所以當發現數據被別的session鎖定中的時候,就會迅速返回ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源。所以在程序中我們可以採用nowait方式迅速判斷當前數據是否被鎖定中,如果鎖定中的話,就要採取相應的業務措施進行處理。
select * from test where id = 10 for update nowait
那這里另外一個問題,就是當我們鎖定住數據的時候,我們對數據進行更新和刪除的話會是什麼樣呢。比如同樣,我們讓第一個Session鎖定住id=10的那條數據,我們在第二個session中執行如下語句。
update test set value=2 where id = 10
這個時候我們發現update語句就好像select for update語句一樣也停住卡在這里,當你第一個session放開鎖定以後update才能正常運行。當你update運行後,數據又被你update語句鎖定住了,這個時候只要你update後還沒有commit,別的session照樣不能對數據進行鎖定更新等等。
總之,Oracle中的悲觀鎖就是利用Oracle的Connection對數據進行鎖定。在Oracle中,用這種行級鎖帶來的性能損失是很小的,只是要注意程序邏輯,不要給你一不小心搞成死鎖了就好。而且由於數據的及時鎖定,在數據提交時候就不呼出現沖突,可以省去很多惱人的數據沖突處理。缺點就是你必須要始終有一條資料庫連接,就是說在整個鎖定到最後放開鎖的過程中,你的資料庫聯接要始終保持住。與悲觀鎖相對的,我們有了樂觀鎖。樂觀鎖一開始也說了,就是一開始假設不會造成數據沖突,在最後提交的時候再進行數據沖突檢測。在樂觀鎖中,我們有3種
常用的做法來實現。
[1]第一種就是在數據取得的時候把整個數據都到應用中,在進行提交的時候比對當前資料庫中的數據和開始的時候更新前取得的數據。當發現兩個數據一模一樣以後,就表示沒有沖突可以提交,否則則是並發沖突,需要去用業務邏輯進行解決。
[2]第二種樂觀鎖的做法就是採用版本戳,這個在Hibernate中得到了使用。採用版本戳的話,首先需要在你有樂觀鎖的資料庫table上建立一個新的column,比如為number型,當你數據每更新一次的時候,版本數就會往上增加1。比如同樣有2個session同樣對某條數據進行操作。兩者都取到當前的數據的版本號為1,當第一個session進行數據更新後,在提交的時候查看到當前數據的版本還為1,和自己一開始取到的版本相同。就正式提交,然後把版本號增加1,這個時候當前數據的版本為2。當第二個session也更新了數據提交的時候,發現資料庫中版本為2,和一開始這個session取到的版本號不一致,就知道別人更新過此條數據,這個
時候再進行業務處理,比如整個Transaction都Rollback等等操作。在用版本戳的時候,可以在應用程序側使用版本戳的驗證,也可以在資料庫側採用Trigger(觸發器)來進行驗證。不過資料庫的Trigger的性能開銷還是比較的大,所以能在應用側進行驗證的話還是推薦不用Trigger。
[3]第三種做法和第二種做法有點類似,就是也新增一個Table的Column,不過這次這個column是採用timestamp型,存儲數據最後更新的時間。在Oracle9i以後可以採用新的數據類型,也就是timestamp with time zone類型來做時間戳。這種Timestamp的數據精度在Oracle的時間類型中是最高的,精確到微秒(還沒與到納秒的級別),一般來說,加上資料庫處理時間和人的思考動作時間,微秒級別是非常非常夠了,其實只要精確到毫秒甚至秒都應該沒有什麼問題。和剛才的版本戳類似,也是在更新提交的時候檢查當前資料庫中數據的時間戳和自己更新前取到的時間戳進行對比,如果一致則OK,否則就是版本沖突。如果不想把代碼寫在程序中或者由於別的原因無法把代碼寫在現有的程序中,也可以把這個時間戳樂觀鎖邏輯寫在Trigger或者存儲過程中。
不知道這個是不是你需要的...
E. 資料庫update默認的是悲觀鎖定還是樂觀鎖
是悲觀鎖還是樂觀鎖,都是人們定義出來的概念,可以認為是一種思想。其實不僅僅是資料庫系統中有樂觀鎖和悲觀鎖的概念,像memcache、hibernate、tair等都有類似的概念。
針對於不同的業務場景,應該選用不同的並發控制方式。所以,不要把樂觀並發控制和悲觀並發控制狹義的理解為DBMS中的概念,更不要把他們和數據中提供的鎖機制(行鎖、表鎖、排他鎖、共享鎖)混為一談。其實,在DBMS中,悲觀鎖正是利用資料庫本身提供的鎖機制來實現的。
F. 悲觀鎖和樂觀鎖的用處和區別
用處:保證數據安全,處理多用戶並發訪問。
區別:
悲觀鎖,從數據開始更改時就將數據鎖住,知道更改完成才釋放。
樂觀鎖,直到修改完成准備提交所做的的修改到資料庫的時候才會將數據鎖住。完成更改後釋放。悲觀鎖會造成訪問資料庫時間較長,並發性不好,特別是長事務。樂觀鎖在現實中使用得較多,廠商較多採用。
G. 悲觀鎖和樂觀鎖,什麼情況
悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關系型資料庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像資料庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
兩種鎖各有優缺點,不可認為一種好於另一種。
像樂觀鎖適用於寫比較少的情況下,即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。
但如果經常產生沖突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
H. 如何驗證資料庫由悲觀鎖改為樂觀鎖
1、悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,因此,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機...
I. 悲觀鎖 和 樂觀鎖 區別
悲觀鎖適用於更改頻繁的數據表,一開始查詢就會上鎖,直至更新操作結束才釋放,性能有所下降,使用select ... from for update。
樂觀鎖適用於更改概率低的數據,只有在提交更新時才釋放,這種方式其實就是自己在表裡面增加一個欄位,例如version(版本)欄位,判斷當前操作的數據是否是同一個版本。
J. 資料庫悲觀鎖有什麼優勢我怎麼覺得他比起樂觀鎖沒什麼優勢,控制並發也不實用,哪位大俠能幫忙舉個必須
網路太垃圾了,這種瞎搗亂的傻逼的號不封,卻把我的號封了,我現在都不在網路知道問問題了,牛人少,還有這種傻逼搗亂