SQLite3 寫資料庫時的鎖機制

2021-05-24 12:24:04 字數 4552 閱讀 3429

**於sqlite官方**上的文件:http://www.sqlite.org/lockingv3.html

sqlite3

寫資料庫

為了寫sqlite3

資料庫,程序必須先獲取

shared

鎖。當獲取

shared

鎖之後,程序需要進一步申請

reserved

鎖。reserved

鎖表示該程序會在不遠的將來執行寫資料庫操作。同一時刻只有乙個程序能夠獲取

reserved

鎖。但是其他程序此時還是可以獲取

shared

鎖來讀取資料庫中的內容

當寫資料庫的程序試圖

reserved

鎖未遂,意味著此時有另乙個程序已經獲取了

reserverd

鎖。在這種情況下,寫資料庫將會失敗,並返回

sqlite_busy

錯誤。獲取

reservered

鎖之後,寫資料庫程序將先建立乙個

rollback journal

。journal

的頭部被初始化成

sqlite

資料庫檔案的原始大小。同時該頭部也為

master journal

保留了空間,儘管該

master-journal

初始值為空。

在對db

的任何乙個

page

(資料是以

page

的形式組織的)

執行更新之前,程序需要將該

page

的原始內容寫到

rollback journal

中。被改變的

page

起初被儲存在記憶體中,並沒有寫到

disk

上。原始的資料庫還是處於未被修改的狀態,換句話說,其它程序還是能繼續讀取原始的資料。

最後,寫資料的程序準備真正更新資料庫了。更新的時機在於

memory cache

滿了需要換出,或者是程序已經準備好

commit

這次update

。在更新發生之前,寫資料庫的程序必須確保沒有其他程序正在讀資料庫,同時

rollback journal

的資料也已經安全儲存到磁碟上,以確保在更新失敗時,

rollback

能夠正確進行。以下將是更新資料庫的具體步驟:

1. 確保所有的

rollback journal

都被寫到

disk

上(而不是os的

fs中或者

disk controller

的cache

中),以防止突然掉電重啟後,資料依然可以恢復。

2. 獲取

pending

鎖,再進一步獲取該資料庫檔案上的

exclusive(排他)

鎖。如果此時該資料庫檔案上有

shared

鎖(被其他程序所占用),寫程序必須等帶直到獲取

exclusive

(排它)鎖。

3. 將

memory

中所有修改過的

page

寫到資料庫檔案中。

如果由於

memory cache

滿了導致的寫資料庫操作,寫程序自己並不知道,也不會立即

commit

。相反,寫程序可能會繼續對記憶體中的

page

作更新操作。在後續的更新被寫到資料庫檔案之前,

rollback journal

必須先被

flush

到disk

上。同時也要注意,先前因為

memory cache

滿而寫資料庫時獲取的

exclusive

(排他)鎖,將會一直保持到所有的更新都被

commit

。換句話說,一旦

memory cache

滿了,並且第一次成功寫入資料庫後,沒有任何其他程序可以訪問資料庫。(排它鎖一旦獲取,就不會降級,直到所有的更新被提交給資料庫)

當乙個寫程序準備

commit

更新時,它將執行一下操作:

4. 獲取該資料庫檔案上的排他鎖,並確保所有

memory

中的更新都正確寫到

disk

上。其邏輯由上述

1-3步驟描述

5. 將所有該資料庫檔案上的更新

flush

到disk

上。(同步過程,資料真正寫到磁碟表面才會返回)

6. 刪除

journal

檔案(如果

pragma journal mode

被設定成

truncate

或者persist

時,則相應地

truncate journal

檔案或者清空

journal

journal

檔案之前,如果出現掉電或者

crash

的情況,當下乙個程序開啟資料庫檔案時,將會發現該資料庫檔案有乙個

hot journal

檔案殘留,並會根據該

journal

檔案回滾所有的更新。當

journal

檔案被刪除後,將不會存在所謂的

hot journal

檔案,所有的更新即被持久化下來。

7. 釋放該資料庫檔案上的

exclusive

鎖和pending鎖一旦

pending

鎖被釋放,其他程序就可以讀取該資料庫檔案中的內容。在當前(

sqlite3

)的實現中,

reserved

鎖也會一同被釋放,雖然無傷大雅。將來的

sqlite

可能會提供

"chech point" sql

命令,可以用來在乙個

transaction

內,提交到當前位置的所有變化,同時保持

reserved

鎖。這樣後續的更新就能確保不會被其他的寫程序搶占。

如果乙個

transaction

涉及到多個

db檔案,提交的邏輯將會更加複雜(

1-3步驟是一樣的,從第

4步開始有所變化):

4. 確保所有的資料庫檔案都獲取到了排它鎖以及正確的

journal

檔案。5.

建立乙個

master-journal

檔案,該

master-journal

檔案的名稱為

arbitray

。(目前的實現是在

"主資料庫檔案

——main database file(

怎麼確定主資料檔案,沒有交代

)"名稱後加乙個隨機數字尾,知道該檔名沒有被使用過為止)該

master-journal

中記錄的是各個db的

journal

檔名稱。(同樣,此時要保證

master-journal

被正確flush

到disk

上)6.

將master-journal

的名稱寫到相關的各個

journal

檔案中(在建立

rollback journal

的時候,為

master journal

預留了空間)。同時

flush

各個journal

檔案到disk

上(是指真正的磁碟表面)。

7. 將資料庫檔案們的更新

flush

到磁碟表面。

8. 提交

transaction

同時,刪除

master-journal

檔案。同理如果在刪除之前,出現掉電,

crash

等情況,參考上個

session的第6

步驟9.

刪除各個

db檔案相關的

journal

檔案10.

釋放相關資料庫檔案上的

exclusive

鎖和pending

鎖寫飢餓

在sqlite2

中,如果有很多程序讀資料庫,很有可能每時每刻都有程序在讀

db。也就是說每時每刻都有程序佔據db的

shared

鎖,寫程序將沒有機會獲取

exclusive

鎖,即導致所謂的寫飢餓。

sqlite 3

通過使用

pending

鎖來解決寫飢餓的問題。

pending

鎖允許當前正在讀

db的程序完成讀操作,但是不允許新的讀操作。因此,當乙個程序準備寫

db時,它將先申請

pending

鎖,阻斷後續的讀操作。而當當前正在讀的所有程序完成讀取操作後,

shared

鎖都被釋放,從而寫程序就可以獲取

exclusive

鎖,進而可以對資料庫進行寫操作。

Sqlite3 資料庫使用

iphone本身是支援 sqlite3 資料庫的,在專案中匯入libsqlite3.dylib。並建立資料庫,在終端,建立資料庫的方式 mkdir sql 建立sql資料夾 cd sql 進入sql目錄下 sqlite3 student.sql 建立名為 student.sql的資料庫 建立表 插入...

sqlite3資料庫操作

1 開啟資料庫 1 需要制定資料庫的路徑 nsstring filepath nshomedirectory documents data.sqlite 2 建立資料庫的物件 sqlite3 qingyundb null 3 開啟命令 sqlite3 open dbfilepath utf8stri...

SQLite3資料庫操作

簡單的sqlite3語句,通過字串拼接執行資料庫操作。1.建立資料庫格式 db.execsql create table if not exists sharp id integer primary key,name varchar,level integer,high integer 其真正的有效...