提到鎖就不得不說到死鎖的問題,而sqlite也可能出現死鎖。
下面舉個例子:
連線1:begin (unlocked)
連線1:select ... (shared)
連線1:insert ... (reserved)
連線2:begin (unlocked)
連線2:select ... (shared)
連線1:commit (pending,嘗試獲取exclusive鎖,但還有shared鎖未釋放,返回sqlite_busy)
連線2:insert ... (嘗試獲取reserved鎖,但已有pending鎖未釋放,返回sqlite_busy)
現在2個連線都在等待對方釋放鎖,於是就死鎖了。當然,實際情況並沒那麼糟糕,任何一方選擇不繼續等待,回滾事務就行了。
不過要更好地解決這個問題,就必須更深入地了解事務了。
實際上begin語句可以有3種起始狀態:
deferred:預設值,開始事務時不獲取任何鎖。進行第一次讀操作時獲取shared鎖,進行第一次寫操作時獲取reserved鎖。
immediate:開始事務時獲取reserved鎖。
exclusive:開始事務時獲取exclusive鎖。
現在考慮2個事務在開始時都使用immediate方式:
連線1:begin immediate (reserved)
連線1:select ... (reserved)
連線1:insert ... (reserved)
連線2:begin immediate (嘗試獲取reserved鎖,但已有reserved鎖未釋放,因此事務開始失敗,返回sqlite_busy,等待使用者重試)
連線1:commit (exclusive,寫入完成後釋放)
連線2:begin immediate (reserved)
連線2:select ... (reserved)
連線2:insert ... (reserved)
連線2:commit (exclusive,寫入完成後釋放)
這樣死鎖就被避免了。
而exclusive方式則更為嚴苛,即使其他連線以deferred方式開啟事務也不會死鎖:
連線1:begin exclusive (exclusive)
連線1:select ... (exclusive)
連線1:insert ... (exclusive)
連線2:begin (unlocked)
連線2:select ... (嘗試獲取shared鎖,但已有exclusive鎖未釋放,返回sqlite_busy,等待使用者重試)
連線1:commit (exclusive,寫入完成後釋放)
連線2:select ... (shared)
連線2:insert ... (reserved)
連線2:commit (exclusive,寫入完成後釋放)
不過在併發很高的情況下,直接獲取exclusive鎖的難度比較大;而且為了避免exclusive狀態長期阻塞其他請求,最好的方式還是讓所有寫事務都以immediate方式開始。
順帶一提,要實現重試的話,可以使用sqlite3_busy_timeout()或sqlite3_busy_handler()函式。
由此可見,要想保證執行緒安全的話,可以有這4種方式:
jupyter notebook可能出現的問題
首頁 專欄python 文章詳情 1 無道 發布於 2020 07 23 環境 anaconda,python3.7,jupyter notebook,win10 終端上配置有多個conda的python環境,在使用jupyter notebook時需要使用其中的乙個環境,但是其預設還是使用系統py...
創新也可能導致平庸
以前考托福時,新東方的老師給我們講外國人 不好好回答問題 的思維,例如,當女生問男生 你愛我嗎?他會回答 冰是冷的嗎?這時我們的選項就應該選擇yes,因為這種回答表明男生是愛這個女生的。小的時候,經歷過乙個很經典的案例 老師在問我們雪化了變成什麼時?我們這群 好 孩子都一致回答 水 只有我的乙個非常...
為什麼會出現死鎖
今天在閱讀 我在思考乙個 如何可以抵擋得住大的迸發量,我先羅列我應該會設計的方案,然後再分析其中實現應該注意的地方 首先如果資料量很大的話,我們是要分散請求的,也就是需要伺服器來聯合作戰,當然這裡我們就需要有乙個好的輪詢的演算法,不然會出現資料無法保持一致而導致程式中隱藏bug,所以說,考慮的方面不...