你真的懂for update?(面試必備)


  溫馨提示: 本文總共3890字,閱讀完大概需要3-6分鐘,希望您能耐心看完,倘若你對該知識點已經比較熟悉,你可以直接通過目錄跳轉到你感興趣的地方,希望閱讀本文能夠對您有所幫助,如果閱讀過程中有什麼好的建議、看法,歡迎在文章下方留言或者私信我,您的意見對我非常寶貴,再次感謝你閱讀本文。

一: 使用場景
一: 使用場景

(一) : 你是否在開發中會經常遇到下面的疑惑呢?

    1、某段代碼在併發的情況下可能會出現線程安全問題,該用什麼方式來防止這種情況的出現呢?

    2、可能你瞭解到可以使用Synchronized關鍵字來處理,但是Synchronized是通過悲觀鎖來實現的,你還會考慮到如果鎖的範圍太大,會很因影響到代碼執行的效率,同時,Synchronized只適用於單機版,如果存在集羣情況下(現在都流行分佈式,這個情況也難免會遇到),它並不能保障不出現併發問題,那麼,此時該使用什麼方式來解決呢?

    3、你可能又瞭解到可以使用Redis的分佈式鎖,或者使用Zookeeper來解決,但是這個又比較麻煩,是否還存在其他的方式呢?

    4、面試時被問到: 在你開發過程中,保障線程安全除了使用Synchronized,你還使用過其他的方式?能夠簡單的說說使用的方式和原理?

(二) : 閱讀完以上的問題,如果你在開發中有遇到過類似的,但沒有找到比較好的解決方式的話,就繼續往下閱讀文章吧,或許你能夠在其中找到一些些幫助。

二: 保證線程安全的新方法
二: 保證線程安全的新方法

  (一)閱讀完上面的問題後,你會發現使用Synchronized不能完全滿足你的需求,使用Redis等分佈式鎖又比較麻煩,是不是還要更好的方法來處理這個問題呢? 是的,那就是我們本文的主角 For update,它可以幫你解決這個疑惑,從此走上發財致富的道理(笑…),下面我們就具體來了解下今天的主角吧。

  (二)For Update是什麼?

         定義: for update是一種行級鎖,又叫排它鎖,一旦用戶對錶某個行記錄施加了行級加鎖,則該用戶可以查詢也可以更新被加鎖的數據行,其它用戶只能查詢但不能更新被加鎖的數據行,如果其它用戶想更新該表中的數據行,則也必須對該表施加行級鎖.即使多個用戶對一個表均使用了共享更新,但也不允許兩個事務同時對一個表進行更新,真正對錶進行更新時,是以獨佔方式鎖表,一直到提交或復原該事務爲止。行鎖永遠是獨佔方式鎖。

        看完定義後是不是感覺還是有點懵逼呀? 那麼我們就用通俗的話來它是什麼意思: 簡單地講for update就是將原來我們在代碼裏面加鎖的情況轉移到在數據庫操作時進行加鎖,通過它,我們不需要在代碼邏輯中手動進行加鎖,只需要在需要操作的記錄時使用select 結合for update即可鎖定數據,但是兩個事務不能同時操作被鎖定的數據,只有等一個事務提交完後另一個事務才只能操作,從而保證了線程安全問題。

        通常情況下,select語句是不會對數據加鎖,妨礙影響其他的DML和DDL操作。select … for update 語句是我們經常使用手工加鎖語句。

  (二)For Update有什麼特點?

  1. Mysql中For update僅適用於Innodb, 且必須在事務處理模塊(BEGIN/COMMIT)中才能生效 。Postgresql的話可以直接使用(下面會使用案例說明)
  2. For Update雖然是行級鎖,但是並不所有的情況下都只鎖行,某些情況下也會將整個表鎖住
  3. 常見的鎖表情況如下(假設存在某個表user,主鍵爲:id):
(1)查詢不明確指定主鍵,:(注意時測試時需要開啓事務)
select * from user for update; // 鎖住整個表
select * from user where id <> 3 for update; // 鎖住整個表
......
(2)查詢中沒有主鍵的時候,:
select * from user where name = 'abc' for update;// 鎖住整個表
......
  1. 常見的不鎖表情況如下(假設存在某個表user,主鍵爲:id):
(1)明確指定主鍵,且數據存在時,:(注意時測試時需要開啓事務)
select * from user where id= 3 for update; // 鎖住ID爲3的行數據
(2)明確指定主鍵,但數據不存在時,如
select * from user where id= 30000 for update;  // 沒有鎖
  1. 測試提示: 可以利用MySQL的Command Mode(命令模式) ,開兩個視窗來做測試。
    測試窗口.
三: 實際使用場景
三: 實際使用場景

1、藉助for update語句,我們可以在應用程序的層面手工實現數據加鎖保護操作。就是那些需要業務層面數據獨佔時,可以考慮使用for update。

2、場景上,比如訂票場景下,在應用顯示有票,但是真正進行出票時,我們需要重新確定這個數據沒有被其他客戶端修改。所以,在這個確認過程中,可以使用for update。

四: 測試實例
四: 測試實例

(一)Mysql數據庫測試結果(需要開啓事務進行測試)

 //mysql的innodb引擎(MyISAM引起無效)
 // 注: Mysql測試時可以開啓兩個控制檯進行,Postgresql可以藉助Navicat軟件
--: 如果不開啓事務的話,使用for update無法鎖住表,增刪查改都可以
--: 只有一個窗口開啓事務,並且鎖定某個記錄,另一個不開啓事務時對數據庫的操作,出現以下的情況
  	1、查詢可以使用
	2、更新不可以使用
	3、刪除記錄不可以使用
	4、插入記錄也可以
--: 只有一個開啓事務,並且鎖定整個表,另一個不開啓事務時對數據庫的操作,出現以下的情況
	1、查詢可以使用
	2、插入可以使用
	3、刪除不可以使用
	4、更新不可以使用
--: 兩邊都開啓事務時,出現以下的情況
	1、查詢可以使用
	2、插入可以使用
	3、刪除不可使用
	4、更新不可以使用

(二)PostgreSQL數據庫測試結果(需要開啓事務進行測試)


--- 沒開啓事務,使用for update時,兩個窗口增刪查改操作都可以

--- 一邊開啓事務,使用for update鎖定某條記錄,一邊不開啓事務,看是否能夠插入,刪除,更新,查詢:
  	1、查詢可以使用
	2、更新不可以使用
	3、刪除記錄不可以使用
	4、插入記錄也可以
	insert into t_user(name) values('abc22'); -- 可以
	update t_user set name ='測試' where id =4; -- 除了被鎖定的記錄外,可以修改其他的記錄
	delete from t_user where id =2; --除了被鎖定的記錄外,可以刪除其他的記錄
	select * from t_user where id =6; -- 所以的記錄都可以查詢

--- 一邊開啓事務,使用for update鎖定整個表,一邊不開啓事務,看是否能夠插入,刪除,更新,查詢
	1、查詢可以使用
	2、插入可以使用
	3、刪除不可以使用
	4、更新不可以使用
	insert into t_user(name) values('abc22'); -- 可以
	update t_user set name ='測試' where id =9; -- 所有不可以被修改
	delete from t_user where id =9; --所有的不可以被刪除
	select * from t_user where id =6; -- 所有的記錄都可以查詢


--- 兩邊同時開始事務,看是否能夠插入,刪除,更新,查詢(鎖定id爲9的記錄)
	1、查詢可以使用
	2、插入可以使用
	3、刪除不可使用
	4、更新不可以使用
	begin;
	insert into t_user(name) values('abc22'); -- 可以
	update t_user set name ='測試' where id =9; -- 不可以被修改,除了記錄9外都可以刪除
	delete from t_user where id =9; --不可以被刪除,除了記錄9外都可以刪除
	select * from t_user where id =6; -- 所有的記錄都可以查詢
	commit;
五: 總結
五: 總結

      通過上面的案例分析發現,For update可以很好的解決Synchronized集羣情況下的線程安全問題以及替換使用分佈式鎖比較麻煩的問題,但是需要注意必須是在事務開啓的前提下,同時,使用For update時需要儘量避免鎖表的情況出現,有主鍵的時候儘量指定主鍵。

      最後,非常感謝你的閱讀,如果有什麼疑問或者建議,歡迎在文章下方留言或者私信我,你的意見對我非常重要,你的肯定對我非常重要,如果你感覺本文對你有一點幫助,麻煩給我點一下贊和關注,後面還會書寫更多的文章跟大家分享其他的知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章