我們有時(shí)候要對(duì)讀出的數(shù)據(jù)做變更,如果使用常規(guī)的select讀出來(lái),再u(mài)pdate,那么可能在update之前,其他的事務(wù)對(duì)所讀的數(shù)據(jù)做了修改,這時(shí)我們之前讀到的數(shù)據(jù)就變成了臟數(shù)據(jù)。針對(duì)這種需求,oracle提供了兩者類(lèi)型的讀鎖:
- 共享讀鎖
SELECT ... LOCK IN SHARE MODE
使用共享鎖讀數(shù)據(jù),其他的事務(wù)也能對(duì)這些數(shù)據(jù)執(zhí)行讀操作。但只能等到共享鎖讀事務(wù)提交后才能執(zhí)行修改操作。
如果在共享鎖讀之前,其他的事務(wù)正在對(duì)這些數(shù)據(jù)做更新,則當(dāng)前的讀操作會(huì)等其他事務(wù)結(jié)束后,再讀最新的數(shù)據(jù)來(lái)做修改。
事務(wù)提交后,共享鎖才會(huì)被釋放。
共享鎖一般在不互斥讀的場(chǎng)景下使用,即對(duì)讀的要求不嚴(yán)格。比如child表,主鍵用一個(gè)counter的變量通過(guò)遞增的方式生成,如果使用共享鎖,則兩個(gè)會(huì)話讀到的數(shù)據(jù)可能會(huì)一致,這會(huì)導(dǎo)致提交的修改也會(huì)一致,結(jié)果會(huì)導(dǎo)致主鍵沖突。
2.互斥讀鎖
SELECT ... FOR UPDATE
互斥讀鎖會(huì)鎖住符合條件的行,以及與其相關(guān)的索引列表,跟我們使用update語(yǔ)句對(duì)這些行做操作一樣。
其他事務(wù)在這些行上的更新操作將會(huì)被阻塞,如共享讀更新,或者某些隔離級(jí)別的讀更新事務(wù)。
互斥讀鎖只有在使用事務(wù)( START TRANSACTION ),或者關(guān)閉自動(dòng)提交(將autocommit設(shè)為0)的情況下才起作用。否則如果允許自動(dòng)提交,使用互斥讀鎖時(shí)符合條件的行不會(huì)被鎖。
針對(duì)上面那種情況,我試了下不在方法上開(kāi)啟(annotation方式)spring的聲明式事務(wù),使用互斥讀鎖也能鎖到符合條件的行,使用hibernate的upgrade_wait lock_mode,但方法結(jié)束后鎖并未被釋放,如果SELECT ... FOR UPDATE的后面緊接著使用 UPDATE ... SET ...更新這些數(shù)據(jù),則會(huì)造成死鎖。為什么會(huì)出現(xiàn)這種情況,目前還未找到原因。
參考資料:
官方文檔 SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads