mysql中select?*?for?update
注:
?for update 僅適用于innodb,且必須在事務區塊(begin/commit)中才能生效。
作用
鎖定該語句所選擇到的對象。防止在選擇之后別的地方修改這些對象造成數據不一致。要保證在統計(查詢)執行過程中,記錄不被其他用戶更新,
則可以使用For?update子句進行加鎖。這樣在這個鎖釋放前其他用戶不能對這些記錄作update、delete和加鎖。
Select???daptno???from????dept?Where???deptno=25???For?update;
如果你使用了FOR?UPDATE來對表進行加鎖,則必須用commit來釋放加鎖的記錄。
鎖分成兩類:加鎖范圍子句和加鎖行為子句 加鎖范圍子句: 在select…for update之后,可以使用of子句選擇對select的特定數據表進行加鎖操作。默認情況下,不使用of子句表示在select所有的數據表中加鎖 加鎖行為子句: 當我們進行for update的操作時,與普通select存在很大不同。一般select是不需要考慮數據是否被鎖定,最多根據多版本一致讀的特性讀取之前的版本。
規則 for UPDATE語句將鎖住查詢結果中的元組,這些元組將不能被其他事務的UPDATE,delete和for UPDATE操作,直到本事務提交。
應用場景
那么,什么時候需要使用for update?就是那些需要業務層面數據獨占時,可以考慮使用for update。場景上,比如火車票訂票,在屏幕上顯示余票,而真正進行出票時,需要重新確定一下這個數據沒有被其他客戶端修改。所以,在這個確認過程中,可以使用for update。這是統一的解決方案方案問題,需要前期有所準備。
由于InnoDB預設是Row-Level?Lock,所以只有「明確」的指定主鍵,mysql才會執行Row?lock?(只鎖住被選取的資料例)?,否則MySQL將會執行Table?Lock?(將整個資料表單給鎖住)。
舉例1
給你舉幾個例子:
select?*?from?t?for?update?會等待行鎖釋放之后,返回查詢結果。 select?*?from?t?for?update?nowait?不等待行鎖釋放,提示鎖沖突,不返回結果 select?*?from?t?for?update?wait?5?等待5秒,若行鎖仍未釋放,則提示鎖沖突,不返回結果 select?*?from?t?for?update?skip?locked?查詢返回查詢結果,但忽略有行鎖的記錄
SELECT…FOR UPDATE 語句的語法如下:?
SELECT?...?FOR?UPDATE?[OF?column_list][WAIT?n|NOWAIT][SKIP?LOCKED];
其中:?
OF 子句用于指定即將更新的列,即鎖定行上的特定列。?
WAIT 子句指定等待其他用戶釋放鎖的秒數,防止無限期的等待。
“使用FOR UPDATE WAIT”子句的優點如下:?
1防止無限期地等待被鎖定的行;?
2允許應用程序中對鎖的等待時間進行更多的控制。?
3對于交互式應用程序非常有用,因為這些用戶不能等待不確定?
4 若使用了skip locked,則可以越過鎖定的行,不會報告由wait n 引發的‘資源忙’異常報告
舉例2
假設有個表單products?,里面有id跟name二個欄位,id是主鍵。
例1:?(明確指定主鍵,并且有此筆資料,row?lock)
SELECT?*?FROM?products?WHERE?id='3'?FOR?UPDATE; SELECT?*?FROM?products?WHERE?id='3'?and?type=1?FOR?UPDATE;
例2:?(明確指定主鍵,若查無此筆資料,無lock)
SELECT?*?FROM?products?WHERE?id='-1'?FOR?UPDATE;
?
例2:?(無主鍵,table?lock)
SELECT?*?FROM?products?WHERE?name='Mouse'?FOR?UPDATE;
?
例3:?(主鍵不明確,table?lock)
SELECT?*?FROM?products?WHERE?id'3'?FOR?UPDATE;
?
例4:?(主鍵不明確,table?lock)
SELECT?*?FROM?products?WHERE?id?LIKE?'3'?FOR?UPDATE;
?
注1:?FOR?UPDATE僅適用于InnoDB,且必須在交易區塊(BEGIN/COMMIT)中才能生效。
注2:?要測試鎖定的狀況,可以利用MySQL的Command?Mode?,開二個視窗來做測試。
?
在MySql?5.0中測試確實是這樣的。
另外:MyAsim?只支持表級鎖,InnerDB支持行級鎖。
添加了(行級鎖/表級鎖)鎖的數據不能被其它事務再鎖定,也不被其它事務修改(修改、刪除)是表級鎖時,不管是否查詢到記錄,都會鎖定表。
此外,如果A與B都對表id進行查詢但查詢不到記錄,則A與B在查詢上不會進行row鎖,但A與B都會獲取排它鎖,此時A再插入一條記錄的話則會因為B已經有鎖而處于等待中,此時B再插入一條同樣的數據則會拋出Deadlock?found?when?trying?to?get?lock;?try?restarting?transaction然后釋放鎖,此時A就獲得了鎖而插入成功。
知識補充
鎖是數據庫中的一個非常重要的概念,它主要用于多用戶環境下保證數據庫完整性和一致性。 我們知道,多個用戶能夠同時操縱同一個數據庫中的數據,會發生數據不一致現象。即如果沒有鎖定且多個用戶同時訪問一個數據庫,則當他們的事務同時使用相同的數據時可能會發生問題。這些問題包括:丟失更新、臟讀、不可重復讀和幻覺讀:
1.當兩個或多個事務選擇同一行,然后基于最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最后的更新將重寫由其它事務所做的更新,這將導致數據丟失。例如,兩個編輯人員制作了同一文檔的電子復本。每個編輯人員獨立地更改其復本,然后保存更改后的復本,這樣就覆蓋了原始文檔。最后保存其更改復本的編輯人員覆蓋了第一個編輯人員所做的更改。如果在第一個編輯人員完成之后第二個編輯人員才能進行更改,則可以避免該問題。
2. 臟讀就是指當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據,那么另外一個事務讀到的這個數據是臟數據,依據臟數據所做的操作可能是不正確的。例如,一個編輯人員正在更改電子文檔。在更改過程中,另一個編輯人員復制了該文檔(該復本包含到目前為止所做的全部更改)并將其分發給預期的用戶。此后,第一個編輯人員認為目前所做的更改是錯誤的,于是刪除了所做的編輯并保存了文檔。分發給用戶的文檔包含不再存在的編輯內容,并且這些編輯內容應認為從未存在過。如果在第一個編輯人員確定最終更改前任何人都不能讀取更改的文檔,則可以避免該問題。
3.不可重復讀是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重復。如果只有在作者全部完成編寫后編輯人員才可以讀取文檔,則可以避免該問題。
?
4.幻覺讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,以后就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。例如,一個編輯人員更改作者提交的文檔,但當生產部門將其更改內容合并到該文檔的主復本時,發現作者已將未編輯的新材料添加到該文檔中。如果在編輯人員和生產部門完成對原始文檔的處理之前,任何人都不能將新材料添加到文檔中,則可以避免該問題。
????? 所以,處理多用戶并發訪問的方法是加鎖。鎖是防止其他事務訪問指定的資源控制、實現并發控制的一種主要手段。當一個用戶鎖住數據庫中的某個對象時,其他用戶就不能再訪問該對象。加鎖對并發訪問的影響體現在鎖的粒度上。為了控制鎖定的資源,應該首先了解系統的空間管理。
以上就是?mysql進階(四)mysql中select的內容,更多相關內容請關注PHP中文網(www.php.cn)!