CREATE TABLE "TEST6" ( "ID" VARCHAR2(30), "NAME" VARCHAR2(30), "AGE" NUMBER(2,0), "SEX" VARCHAR2(2), "ENAME" VARCHAR2(30), "ADDTIME" DATE ) insert into TEST6 (id, name, age, sex, ename, addtime) values ('1', '張三', 18, null, 'zhangsan', to_date('14-03-2017 00:00:09', 'dd-mm-yyyy hh24:mi:ss')); insert into TEST6 (id, name, age, sex, ename, addtime) values ('2', '李四', null, '1', 'Lisi', to_date('01-03-2017 02:00:00', 'dd-mm-yyyy hh24:mi:ss')); insert into TEST6 (id, name, age, sex, ename, addtime) values ('3', '王五', 20, '0', 'wangwu', to_date('09-01-2017 08:55:00', 'dd-mm-yyyy hh24:mi:ss')); insert into TEST6 (id, name, age, sex, ename, addtime) values ('4', '趙六', 23, '0', 'zhaoliu', to_date('03-03-2016 04:00:00', 'dd-mm-yyyy hh24:mi:ss')); insert into TEST6 (id, name, age, sex, ename, addtime) values ('5', '馮七', 22, null, 'fengqi', to_date('08-03-2017 12:00:01', 'dd-mm-yyyy hh24:mi:ss'));
CREATE TABLE "TEST8" ( "ID" NUMBER, "ORDERID" NUMBER, "PRODUCTID" NUMBER, "PRICE" NUMBER(10,2), "QUANTITY" NUMBER ) insert into TEST8 (id, orderid, productid, price, quantity) values (1, 1, 1, 6, 10); insert into TEST8 (id, orderid, productid, price, quantity) values (2, 1, 2, 4, 5); insert into TEST8 (id, orderid, productid, price, quantity) values (3, 1, 3, 10, 2); insert into TEST8 (id, orderid, productid, price, quantity) values (4, 2, 1, 3, 6); insert into TEST8 (id, orderid, productid, price, quantity) values (5, 2, 2, 4, 6);
以上是基礎數據sql
在oracle中,若是隻進行select語句的話,是不會進行加鎖的,也就是oracle會返回當前時刻的結果集,即便這個時候可能有另一個進程在修改當前結果集的數據,由於沒有加鎖,因此oracle仍是會正常的返回當前時刻的結果集,不會有任何影響。session
他們三個共同點:oracle
當使用select for update 或者select for update wait或者.....,那麼oralce會給符合where條件的數據行加上一個行級鎖測試
一、select for updatespa
可是若是你的select 語句加了for update,那麼就不是上面這回事了,當oracle發現select的當前結果集中的一條或多條正在被修改(注意:當數據被修改時,此時的數據行是被加鎖的),那麼他就會等到當前當前結果集被修改完畢而且commit以後才進行select操做,並對結果集進行加鎖。一樣的,若是查詢語句發出後,其餘會話須要修改結果集中的一條(或幾條數據)也許要等到查詢結束(commit)以後,才能夠執行修改操做。3d
代碼以下:code
新建SQL窗口1,(至關於新建一個session會話)blog
select * from test8 for update
for update 對整個結果集進行了加鎖,意味着在當前session進行commit以前,任何其餘的session進行update、delete、insert操做都會進行等待進程
新建SQL窗口2(至關於新建一個session會話)事務
update test8 set price=6 where ID=1
顯示執行中,等待會話一的查詢執行完成
如今咱們將會話一的事務提交(commit)
會話二的update語句執行成功
二、select for update nowait
for update和for update nowait都會對查詢到的當前結果集進行加鎖,所不一樣的是,當有另外的會話在修改當前結果集中的數據,select for nowait所進行的查詢操做不會進行等待,當發現結果集中的一些數據被加鎖,馬上返回 「ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源」。測試代碼以下:
新建一個SQL窗口1(至關於新建一個會話)
update test8 set price=3 where ID=1
更新test8表的一條數據,可是不進行commit操做
而後新建SQL窗口2(至關於新建一個會話)select for update nowait操做
select * from test8 for update nowait
總結分析:
由於會話一,並無commit因此test8中的ID=1的行被加鎖了,因此當會話二進行select for update nowait檢索到ID=1的數據行被加鎖了,就馬上返回 「ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源」的錯誤。
接下來咱們對會話一進行commit操做,
在執行會話二的select查詢,ok,能夠查出來了,而且對當前數據集進行了加鎖操做,其餘會話想要進行修改操做,必須等到會話二commit以後
三、select for update wait
它也會對查詢到的結果集進行加鎖,select for update wait與select for update nowait不一樣的地方是,當有另外的會話對它的查詢結果集中的某一行數據進行了加鎖,那麼它不會像nowait同樣,當即返回"ORA-00054錯誤",而是它支持一個參數,設定等待的時間,當超過了設定的時間,那一行數據還處於加鎖的狀態,那麼它也會返回「ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源」。測試代碼以下:
首先新建SQL窗口1(至關於新建一個會話)執行update 語句,可是不進行commit操做,那麼當前數據行將被lock
update test8 set price=3 where ID=1
接着新建SQL窗口2(至關於新建一個會話),在執行select for update wait 6,若是當前查詢檢索的數據集中,有被加鎖了的行數據,那麼等待6秒,若是6秒後,其餘會話,尚未執行commit釋放被加了鎖的數據行的話,那麼返回「ORA-00054錯誤,內容是資源正忙, 但指定以 NOWAIT 方式獲取資源」。
select * from test8 for update wait 6
執行語句6秒後,報錯。
最後對會話一(SQL窗口一)進行commit操做
緊接着執行會話二(SQL窗口二)中的sql語句,此時被加鎖的數據行被釋放
正常的檢索除了數據行,當時當前數據集被加鎖,其餘會話想操做此數據集,必須等會話二中的事務commit以後,才能夠進行修改
四、OF子句
在多表查詢中若是須要對多表查詢的結果集進行加鎖,可使用OF子句。
若是存在OF子句,那麼就對知足OF子句的單表進行加鎖,若是不存在OF子句就對整個結果集進行加鎖,代碼以下:
a、不使用OF子句
select a.ID,a.Name,b.price from test6 a LEFT JOIN test8 b ON a.ID=b.ID where b.ID>3 for update
沒有進行commit操做,此時對test6和test8中的ID>3的數據行都進行了加鎖,測試代碼以下:
新建一個會話,執行如下語句:
select * from test6 for update skip locked
select * from test8 for update skip locked
測試結果證實,在沒有OF子句的狀況下,對多表查詢的結果集進行select foe update,oracle會對知足where 條件的全部數據行進行加鎖
b、使用OF子句
使用OF子句,那麼oracle就會對知足OF子句的表進行加鎖,在多表查詢中。代碼以下:
select a.ID,a.Name,b.price from test6 a LEFT JOIN test8 b ON a.ID=b.ID where b.ID>3 for update of a.ID
在不執行commit操做的狀況,新建一個會話,執行一下語句:
select * from test6 for update skip locked
select * from test8 for update skip locked
比對測試結果,發如今OF子句的做用下,oracle對同時知足where子句(設置要加鎖的數據行)和OF子句(主要設置加鎖的表)的數據行進行了加鎖。