Oracle中鎖分為這麼幾種類型(阻塞、一致性讀、當前讀),按照類型分為(排它鎖(X鎖)、共享鎖(S鎖)),按鎖定對象分為(DML鎖、DDL鎖、內存鎖(Latch))
1. DML鎖 又分為兩種:
l TX 鎖:即事務鎖,如果 insert,update,delete,merge
select …..for update ,會對所操作的行加TX鎖,TX鎖是行級別鎖。
l TM鎖:進行DML操作時加在表級對象上的鎖,防止其他對象對錶結構加X類型鎖,分如下級別:
2(RS,row share) 3(RX,row exclusive) 4(S,share)
5(SRX,share row exclusive) 6(X, exclusive)
例如 for update 阻塞 X 類型的DDL語句
Session 1: select * from test where a=100 for update;
Session 2: truncate table test;
會報如下錯誤:ORA—00054:resource busy and acquire with NOWAIT specified
注意:在一個session 中,TX鎖一般只會有一個,因為只有一個事務,而TM鎖可以有多個,因為在一個會話中,可能更新多張表。
2. DDL 鎖主要分兩類:
l X 類型DDL :多發生在 truncate,drop,alter table drop/add/modify
等絕大部分DDL上,操作期間會給表加X類型TM鎖。
l S類型DDL:如online操作,會在表上加一個RS(2級)類型的TM鎖,因為RS類型鎖可以在加RX(3級)鎖,所以 online 操作不阻塞 DML語句。
例:創建索引和online創建索引的差別
l 當執行下列SQL: create index idx_test1 on test(object_id);
創建索引時在 test 上會加級別為 4的 S鎖,會阻塞級別為3的RX鎖所以創建索引時不能正常DML,因為DML要加RX鎖。
l 執行下列SQL: create index idx_test1 on test(object_id) online;
如果添加 online ,在test上面會加最低級別(2級)的RS鎖,這個類型的TM鎖允許加更高級別的RX鎖,所以online操作時可以執行DML。
3. 內存鎖:
也叫 latch ,是一個運行在內存中,保護內存結構的輕量級鎖,latch資源很寶貴,如果處理不好,將浪費很大的cpu來管理內存鎖,比較典型的就是硬解析。
4. Oracle阻塞分三類: TX 阻塞, TM阻塞, Latch 阻塞
l TX 阻塞:行級阻塞,比如一個會話對一行加了TX鎖,另外會話在對這個行加TX鎖時失敗,於是產生了阻塞。
l 行級別的等待與TX鎖都不太耗費資源,事務記錄在數據塊的事務槽內(ITL)。
l TM阻塞:表級鎖 ,下面用 lock模擬一下表創建索引的情況。
Session 1: SQL> lock table test in share mode;
Session 2: SQL> update test set b=100 where a=5;
當 session2 執行update時發生阻塞, 當執行update時加 TX鎖之前,加TM鎖(update應該加 級別為 3的RX類型鎖)加不上,導致等待,因為 session1已經添加了更高級別4(S)級的TM鎖
除了 TX 和 TM阻塞外,latch 也會發生阻塞,並且可以阻塞 select 語句。
例:在一個大表上創建約束,oracle 自動創建索引,從而導致表屬性變化,如果創建索引時間很長將導致 select 阻塞在 library cache lock 上,不能獲得句柄(handle)信息,從而不能分析語句。
所以證明並不是所有oracle 操作都是不阻塞的,大數據量高併發環境在線維護應儘量避免鎖和阻塞。
5. 併發控制(一致性讀)
l 讀已提交(read commited) 和一致性讀(serializable read)
l 例如:
T1 session 1:update test set b=100 where a=‘tom’; not commit;
T2 session 2:select * from test; 看不到 session1 修改的數據
T3 session 1:commit;
T4 session2:
還在執行 select,儘管session1 在T3已經提交,但是查詢出的還是沒修改前的數據,這個叫做 “一致性讀”(oracle 支持)。如果能看到提交後的結果叫做 “讀已提交”。
l 一致性讀原理:oracle 會根據undo重構以前的一致性塊,如果select時間太長undo的數據被覆蓋,或者undo事務表被覆蓋,導致無法重構一致性塊,返回 ORA-01555錯誤。
l 例如:假設 dept只有一條記錄
session 1: select * from dept; logical reads 為 1
session 2:循環 update dept set loc=‘abc’ where deptno=40;修改1000次後不提交
session 1:select * from dept; logical reads 為 1008
這裡發生的 consistent gets 其實是發生在一個數據塊上的,只不過是被rollback多次,重複讀了多次。
6. 併發控制(當前讀)
l 當前讀,只在DML的時候產生,當修改數據時,完成當前最新數據的獲取並在最新的數據上更新,oracle 必須保證更新的連續性。
l 例如:表 test中只有一列,一行數據
session 1:
SQL> select * from test 結果為 1000
SQL> update test set a=a+1 where a=1000 not commit
session 2:
SQL> update test set a=a+1 where a=1000 操作被阻塞
session 1:
SQL> commit; 執行後看到 session 2也更新成功
最後的更新結果為 1001
7. 併發控制
l 悲觀鎖:在更新數據之前會把數據先鎖定,例如:
SQL> select * from test where id=100 for update nowait; 更新行加 RX鎖
SQL> update test set status=‘Y’ where id=100;
SQL> commit;
l 樂觀鎖:利用 oracle 當前讀的 特性,在更新數據時,不是跟 select 一樣發生一致性讀,而是當前讀。例如:
SQL> update test set status=‘Y’ where id=100 and status=‘Y’;
(Tx)
閱讀更多 程序員治百病 的文章