Oracle資料庫資料鎖機制解析(zt)
為了得到最大的效能,一般資料庫都有併發機制,不過帶來的問題就是資料訪問的衝突。為了解決這個問題,大多數資料庫用的方法就是資料的鎖定。
資料的鎖定分為兩種方法,第一種叫做悲觀鎖,第二種叫做樂觀鎖。什麼叫悲觀鎖呢,悲觀鎖顧名思義,就是對資料的衝突採取一種悲觀的態度,也就是說假設資料肯定會衝突,所以在資料開始讀取的時候就把資料鎖定住。而樂觀鎖就是認為資料一般情況下不會造成衝突,所以在資料進行提交更新的時候,才會正式對資料的衝突與否進行檢測,如果發現衝突了,則讓使用者返回錯誤的資訊,讓使用者決定如何去做。
先從悲觀鎖開始說。Oracle用的是行級鎖,只是對想鎖定的資料才進行鎖定,其餘的資料不相干,所以在對Oracle表中併發插資料的時候,基本上不會有任何影響。Oracle的悲觀鎖需要利用一條現有的連線,分成兩種方式,從SQL語句的區別來看,就是一種是for update,一種是for update nowait的形式。比如我們看一個例子。首先建立測試用的資料庫表。
SQL> CREATE TABLE TEST(ID,NAME,LOCATION,VALUE,CONSTRAINT test_pk PRIMARY KEY(ID))AS SELECT deptno, dname, loc, 1 FROM scott.dept;
表已建立。
首先我們執行如下的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中,用這種行級鎖帶來的效能損失是很小的,只是要注意程式邏輯,不要給你一不小心搞成死鎖了就好。而且由於資料的及時鎖定,在資料提交時候就不撥出現衝突,可以省去很多惱人的資料衝突處理。缺點就是你必須要始終有一條資料庫連線,就是說在整個鎖定到最後放開鎖的過程中,你的資料庫聯接要始終保持住。
與悲觀鎖相對的,我們有了樂觀鎖。樂觀鎖一開始也說了,就是一開始假設不會造成資料衝突,在最後提交的時候再進行資料衝突檢測。在樂觀鎖中,最好的方法就是採用Oracle 10g所帶有的ORA_ROWSCN函式來進行樂觀鎖。ORA_ROWSCN是根據系統最後更新時間來進行計算。這個ORA_ROWSCN在預設情況下是採用資料塊為單位的,也就是一個資料庫塊(block)上共享一個ORA_ROWSCN,當資料更新的時候,這個block快的ORA_ROWSCN就會自動更新。所以在預設情況下的話,有可能出現假衝突的情況。比如A,B,C,D四條資料都在一個block上,這個時候A資料更新了, ORA_ROWSCN也會更新,這個時候因為ABCD四條資料儲存在一個block上,所以BCD的ORA_ROWSCN也更新過了,其實BCD三條資料並沒有更新過,這個就造成了假更新的情況出現。如下SQL語句:SQL> select id,name, location,value,ora_rowscn from test;
ID NAME LOCATION VALUE ORA_ROWSCN
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 1 4926165
20 RESEARCH DALLAS 1 4926165
30 SALES CHICAGO 1 4926165
40 OPERATIONS BOSTON 1 4926165
然後執行如下的更新語句:update test set value=2 where id = 20
在資料commit過後,會發現ORA_ROWSCN都發生了變化,如下所示:
SQL> select id,name, location,value,ora_rowscn from test;
ID NAME LOCATION VALUE ORA_ROWSCN
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 1 4926900
20 RESEARCH DALLAS 2 4926900
30 SALES CHICAGO 1 4926900
40 OPERATIONS BOSTON 1 4926900
對於這種情況還是可以有辦法解決的,就是利用Oracle 9i提供的ROWDEPENDENCIES建表關鍵字,這個關鍵字在Oracle9i中是為了增加行依賴性跟蹤特性的,支援推進複製。在 Oracle10g中有可以用來做行級別的ORA_ROWSCN用了。用這個關鍵字建表以後,在每行會增加一個隱藏的COLUMN,所以每行會增加6個byte的開銷。建表語句如下所示:
SQL> CREATE TABLE TEST2(ID,NAME,LOCATION,VALUE,CONSTRAINT test2_pk PRIMARY KEY(ID))ROWDEPENDENCIES AS SELECT deptno, dname, loc, 1 FROM scott.dept;
表已建立。
SQL> select id,name, location,value,ora_rowscn from test2;
ID NAME LOCATION VALUE ORA_ROWSCN
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 1 4943018
20 RESEARCH DALLAS 1 4943018
30 SALES CHICAGO 1 4943018
40 OPERATIONS BOSTON 1 4943018
SQL> update test2 set value=2 where id=20;
已更新 1 行。
SQL> select id,name, location,value,ora_rowscn from test2;
ID NAME LOCATION VALUE ORA_ROWSCN
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 1 4943018
20 RESEARCH DALLAS 2
30 SALES CHICAGO 1 4943018
40 OPERATIONS BOSTON 1 4943018
可以看到在沒提交之前,value為2的ORA_ROWSCN已經為空,
SQL> commit;
提交完成。
SQL> select id,name, location,value,ora_rowscn from test2;
ID NAME LOCATION VALUE ORA_ROWSCN
---------- -------------- ------------- ---------- ----------
10 ACCOUNTING NEW YORK 1 4943018
20 RESEARCH DALLAS 2 4943097
30 SALES CHICAGO 1 4943018
40 OPERATIONS BOSTON 1 4943018
可以看到這次只有id=20的資料的ORA_ROWSCN發生了更新。所以這個時候我們就可以利用ORA_ROWSCN作為樂觀鎖,用不著專門再增加一個額外的域了。而且這個域是Oracle負責維護的,開銷也不是很大,不過需要Oracle 10g才可以使用。
總之,介紹了Oracle的鎖定機制,究竟是悲觀鎖好還是樂觀鎖好,其實也是不一定的。Oracle中悲觀鎖還是很不錯的,而且從開始的時候就把資料鎖定。免除了後面的很多衝突處理。不過悲觀鎖需要保持一個Oracle連線,在我們常見的B/S應用中,特別是資料先取得,然後讓使用者再更新,再返回提交這種流程來說,悲觀鎖是不大可能的。首先是因為B/S應用中,一般是利用一個連線池,在兩次Http Request請求都是不同的資料庫Connection。而且也不能鎖定一個資料太長時間,否則人人都這麼鎖定,應用很容易進入死鎖狀態,這個時候就要採用樂觀鎖了。而在樂觀鎖中,ORA_ROWSCN可以說是比較好的選擇,不過第一需要重新建表,第二需要在Oracle10g下才有這個特性,所以也不是到處都可以使用,當一個萬金油的。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/628922/viewspace-616338/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料庫鎖機制資料庫
- 修改Oracle資料庫字符集(zt)Oracle資料庫
- Oracle多粒度封鎖機制研究二(zt)Oracle
- 資料庫系列:MySQL InnoDB鎖機制介紹資料庫MySql
- 【資料庫】MySQL鎖機制、熱備、分表資料庫MySql
- (資料庫十)資料庫中的鎖機制以及死鎖產生的原因及解決辦法資料庫
- MS SQL Server資料庫事務鎖機制分析(轉)SQLServer資料庫
- 13_深入解析Oracle資料庫bootstrapOracle資料庫boot
- MySQL資料庫InnoDB儲存引擎中的鎖機制GVMySql資料庫儲存引擎
- 學習資料庫索引機制資料庫索引
- SYBASE資料庫dbcc命令詳解(zt)資料庫
- MySQL 資料庫鎖定機制?這篇文章為你分析清楚~MySql資料庫
- DataX將MySql資料庫資料同步到Oracle資料庫MySql資料庫Oracle
- 【NUMBER】Oracle資料庫最佳化之理解NUMBER儲存機制Oracle資料庫
- Oracle資料庫-----資料庫的基本概念Oracle資料庫
- oracle 備份資料庫,匯出資料庫Oracle資料庫
- sqlserver讀取oracle資料庫資料SQLServerOracle資料庫
- oracle資料庫資料字典應用Oracle資料庫
- Oracle資料庫遷移到國產資料庫核心難點解析 | 聯盟釋出Oracle資料庫
- DataX將Oracle資料庫資料同步到達夢資料庫Oracle資料庫
- Oracle資料庫配置Oracle資料庫
- [Oracle]Oracle資料庫資料被修改或者刪除恢復資料Oracle資料庫
- 「Oracle」Oracle 資料庫安裝Oracle資料庫
- 【資料庫資料恢復】如何恢復Oracle資料庫truncate表的資料資料庫資料恢復Oracle
- Oracle資料庫遷移至PolarDb(阿里雲資料庫)Oracle資料庫阿里
- 從 Oracle 日誌解析學習資料庫核心原理Oracle資料庫
- oracle資料庫檢視鎖表的sql語句整理Oracle資料庫SQL
- oracle資料庫事務transaction鎖lock模式思考之一Oracle資料庫模式
- oracle資料庫事務transaction 不同的鎖lock型別Oracle資料庫型別
- 【資料庫資料恢復】誤truncate table的Oracle資料庫資料恢復方案資料庫資料恢復Oracle
- 【資料庫資料恢復】oracle資料庫誤truncate table怎麼恢復資料?資料庫資料恢復Oracle
- 【資料庫資料恢復】Oracle資料庫誤truncate table的資料恢復案例資料庫資料恢復Oracle
- ORACLE 資料塊格式深入解析Oracle
- Oracle資料庫(單機)巡檢報告Oracle資料庫
- Oracle資料庫閃回Oracle資料庫
- oracle資料庫卡頓Oracle資料庫
- 4.2. Oracle資料庫Oracle資料庫
- Laravel 使用 Oracle 資料庫LaravelOracle資料庫
- oracle資料庫建立資料庫例項-九五小龐Oracle資料庫