sqlite3出現SQLITE_BUSY錯誤碼的原因以及解決方法


轉載:https://www.cnblogs.com/lijingcheng/p/4454884.html

轉載:https://blog.csdn.net/venchia_lu/article/details/50456142

轉載:https://blog.csdn.net/guofu8241260/article/details/36378291

轉載:https://www.jianshu.com/p/15051fbd5a35?utm_campaign

轉載:http://www.cnblogs.com/hustcat/archive/2009/03/01/1400757.html

轉載:https://www.cnblogs.com/xienb/p/3455562.html(相同的項目場景)

轉載:http://www.cnblogs.com/gfxxbk/p/5469200.html(錯誤碼)

轉載:https://www.cnblogs.com/feng9exe/p/10682567.html(sqlite線程模型)

轉載:https://www.cnblogs.com/cchust/p/5121559.html(API詳細介紹)

最近項目中涉及到sqlite並發讀寫的問題,先搞清楚sqlite3自身的機制。

1.sqlite3支持多線程同時讀操作,但不支持多線程同時寫操作

2.同一時刻只能有一個線程去進行寫操作,並且在一個線程進行寫操作的時候,其他線程是不能進行讀操作的。

  當一個線程正在寫操作時,其他線程的讀寫都會返回操作失敗的錯誤,顯示數據庫文件被鎖住。

3.sqlite3的鎖類型

  sqlite3總共有三種事務類型:BEGIN [DEFERRED /IMMEDIATE / EXCLUSIVE] TRANSCATION,五種鎖,按鎖的級別依次是:UNLOCKED /SHARED /RESERVERD /PENDING /EXCLUSIVE。

  當執行select即讀操作時,需要獲取到SHARED鎖(共享鎖);

  當執行insert/update/delete操作(即內存寫操作時),需要進一步獲取到RESERVERD鎖(保留鎖),當進行commit操作(即磁盤寫操作時),需要進一步獲取到EXCLUSIVE鎖(排它鎖)。

  對於RESERVERD鎖,sqlite3保證同一時間只有一個連接可以獲取到保留鎖,也就是同一時間只有一個連接可以寫數據庫(內存),但是其它連接仍然可以獲取SHARED鎖,也就是其它連接仍然可以進行讀操作(這里可以認為寫操作只是對磁盤數據的一份內存拷貝進行  修改,並不影響讀操作)。

 對於EXCLUSIVE鎖,是比保留鎖更為嚴格的一種鎖,在需要把修改寫入磁盤即commit時需要在保留鎖/未決鎖的基礎上進一步獲取到排他鎖,顧名思義,排他鎖排斥任何其它類型的鎖,即使是SHARED鎖也不行,所以,在一個連接進行commit時,其它連接是不能做任何操作的(包括讀)。

 PENDING鎖(即未決鎖),則是比較特殊的一種鎖,它可以允許已獲取到SHARED鎖的事務繼續進行,但不允許其它連接再獲取SHARED鎖,當已存在的SHARED鎖都被釋放后(事務執行完成),持有未決鎖的事務就可以獲得commit的機會了。sqlite3使用這種鎖來防止writer starvation(寫餓死)。

  sqlite3只支持庫級鎖,庫級鎖意味着什么?——意味着同時只能允許一個寫操作,也就是說,即事務T1在A表插入一條數據,事務T2在B表中插入一條數據,這兩個操作不能同時進行,即使你的機器有100個CPU,也無法同時進行,而只能順序進行。表級都不能並行,更別說元組級了——這就是庫級鎖。但是,SQLite盡量延遲申請X鎖,直到數據塊真正寫盤時才申請X鎖,這是非常巧妙而有效的。

4.解決方案

對於多線程寫數據庫的情況,Sqlite3不能實現同時寫,但是可以實現串行寫數據,也就是一個線程在寫的時候,其他線程等待,第一個線程寫完的時候,另一個線程獲得數據庫文件鎖開始寫。Sqlite3提供了接口sqlite3_busy_handler(),來實現多線程串行寫數據。BusyHandler其實是一個回調函數。也就是當A線程正在寫操作時,其他線程寫失敗時進行的重試操作,其他線程不斷地調用BusyHandler來進行一些處理,直到自己獲得寫權限之后。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM