爲了獲得最大的性能,通常數據庫都有併發機制,不過帶來的問題就是數據訪問的衝突。爲了解決這個問題,大多數數據庫用的方法就是數據的鎖定。sql
數據的鎖定分爲兩種方法,第一種叫作悲觀鎖,第二種叫作樂觀鎖。什麼叫悲觀鎖呢,悲觀鎖顧名思義,就是對數據的衝突採起一種悲觀的態度,也就是說假設數據確定會衝突,因此在數據開始讀取的時候就把數據鎖定住。而樂觀鎖就是認爲數據通常狀況下不會形成衝突,因此在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,若是發現衝突了,則讓用戶返回錯誤的信息,讓用戶決定如何去作。數據庫
先從悲觀鎖開始說。在SqlServer等其他不少數據庫中,數據的鎖定一般採用頁級鎖的方式,也就是說對一張表內的數據是一種串行化的更新插入機制,在任什麼時候間同一張表只會插1條數據,別的想插入的數據要等到這一條數據插完之後才能依次插入。帶來的後果就是性能的下降,在多用戶併發訪問的時候,當對一張表進行頻繁操做時,會發現響應效率很低,數據庫常常處於一種假死狀態。而Oracle用的是行級鎖,只是對想鎖定的數據才進行鎖定,其他的數據不相干,因此在對Oracle表中併發插數據的時候,基本上不會有任何影響。session
注:對於悲觀鎖是針對併發的可能性比較大,而通常在咱們的應用中用樂觀鎖足以。併發
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用戶的表,把數據copy到咱們的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中你的檢索語句以下所示。spa
select * from test where id = 10;
也就是沒有for update這種鎖定數據的語句的話,就不會形成阻塞了。另一種狀況,就是當數據庫數據被鎖定的時候,也就是執行剛纔for update那條sql之後,咱們在另一個session中執行for update nowait後又是什麼樣呢。好比以下的sql語句。 因爲這條語句中是制定採用nowait方式來進行檢索,因此當發現數據被別的session鎖定中的時候,就會迅速返回ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源。因此在程序中咱們能夠採用nowait方式迅速判斷當前數據是否被鎖定中,若是鎖定中的話,就要採起相應的業務措施進行處理。.net
select * from test where id = 10 for update nowait;
那這裏另一個問題,就是當咱們鎖定住數據的時候,咱們對數據進行更新和刪除的話會是什麼樣呢。好比一樣,咱們讓第一個Session鎖定住id=10的那條數據,咱們在第二個session中執行以下語句。code
update test set value=2 where id = 10;
這個時候咱們發現update語句就好像select for update語句同樣也停住卡在這裏,當你第一個session放開鎖定之後update才能正常運行。當你update運行後,數據又被你update語句鎖定住了,這個時候只要你update後尚未commit,別的session照樣不能對數據進行鎖定更新等等。blog
總之,Oracle中的悲觀鎖就是利用Oracle的Connection對數據進行鎖定。在Oracle中,用這種行級鎖帶來的性能損失是很小的,只是要注意程序邏輯,不要給你一不當心搞成死鎖了就好。並且因爲數據的及時鎖定,在數據提交時候就不呼出現衝突,能夠省去不少惱人的數據衝突處理。缺點就是你必需要始終有一條數據庫鏈接,就是說在整個鎖定到最後放開鎖的過程當中,你的數據庫聯接要始終保持住。與悲觀鎖相對的,咱們有了樂觀鎖。樂觀鎖一開始也說了,就是一開始假設不會形成數據衝突,在最後提交的時候再進行數據衝突檢測。在樂觀鎖中,咱們有3種經常使用的作法來實現。