SQLite數據庫鎖問題

轉自:http://blog.csdn.net/rongyongfeikai2/article/details/41311193


記得以前設計評審時,想用SQLite數據庫實現某個功能,被教導說應該用Postgresql數據庫,因爲Postgresql數據庫是行鎖,而SQLite的鎖粒度太粗了。當時還沒有什麼感覺。

後來在另一個產品的羣裏面,經常看到其中的開發和測試說SQLite數據庫死鎖了。這才留了一下心。

最近又要使用它,於是拜讀了下《SQLite權威指南》,裏面赫赫一句話:SQLite處理併發讀沒有什麼問題,但是如果你的應用需要併發寫的話,那麼SQLite就不適合你了。

看了一下SQLite數據庫的鎖機制:

它包括四種鎖,共享鎖(Shared lock)、預留鎖(Reserved lock)和未決鎖(Pending lock)、排他鎖(Exclusive lock)

其中讀操作,用的是Shared lock,所以併發的多個讀數據庫。如果有一個讀操作存在,那麼都不會允許寫。

而寫就比較麻煩,

1.它首先會申請一個預留鎖(Reserved lock),在啓用Reserved lock之後,已存在的讀可以繼續讀,也可以有新的讀請求。

2.然後,它會把需要更新的數據寫到緩衝區中。

3.需要寫到緩衝區的更新寫完以後,就需要將更新刷到硬盤db了。這時,它會申請Pending lock,就不能再有新的Shared lock申請了,也就是阻止了新的讀操作。但是已經存在的讀操作還是可以繼續讀的。然後它就等待,直到沒有讀操作存在(即所有的讀都已經結束)這個時候,它就會申請排他鎖,此時不允許有其他鎖的存在,然後進行commit,將緩衝區的數據寫入db中。

書上給舉了個例子:

B進行寫操作,申請了預留鎖;然後A進行讀操作,申請了共享鎖(有預留鎖時,是允許讀操作申請的);然後A又同時想進行寫操作(未釋放共享鎖的情況),此時申請預留鎖(因爲已經有預留鎖存在了)失敗;B寫完緩存,想commit時,申請了未決鎖,但是無法從未決鎖提升到排他鎖(因爲有共享鎖存在)。此時,發生死鎖,A和B都想等待對方釋放鎖。


對應一下自己的場景:

1.頁面有多個讀

2.後臺會定時寫

按照書上說的,寫鎖的時長大概是幾毫秒。我寫程序也儘量注意了。也許在極端情況下,在寫時,恰好有讀鎖未釋放,不過幾毫秒內,概率不算很大。

另外,就算是這種極端情況未寫成功,在下一個5分鐘寫時,也會把上一個5分鐘未commit的給補救上去。從前臺看來,就是數據會有一定時延。


另外一個隱含的需求:頁面可能也需要進行更新數據的操作,這個寫是有用戶的某個動作觸發的,那麼在多用戶的情況下,讀寫同時、寫寫同時的概率就會很大。對此,希望是採取規避的方式,在後臺提供與此更新操作的腳本,而非在前臺頁面提供。


由此可見,SQLite作爲一個嵌入式數據庫,不太適合用在高併發的場景下;另外,以上都是理論,希望有時間閱讀源碼,能夠徹底弄清楚一切。

討論了下,爲了規避風險,還是不用SQLite了。什麼時候,SQLite才能把數據庫級別的鎖改爲行鎖?不過如果真的SQLite支持行鎖,那麼就違背它輕量、簡單的初衷了。所以,這個終究是一個夢。


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