Sqlite學習筆記 五 SQLite封鎖機制

2021-07-04 21:39:47 字數 4512 閱讀 5728

概述

sqlite雖然是乙個輕量的嵌入式資料庫,但這並不影響它支援事務。所謂支援事務,即需要在併發環境下,保持事務的acid特性。

事務的原子性,隔離性都需要通過併發控制來保證。那麼sqlite的併發控制是怎樣的,如何實現,在這裡跟大家分享下我的理解。

sqlite是乙個檔案資料庫,所有的資料都在乙個db檔案中,對於wal模式,還包含wal索引檔案和wal日誌檔案。

sqlite支援庫級併發,即允許多個讀事務同時執行,同一時刻最多只有乙個寫事務,讀寫衝突,相對於傳統的dbms支援表級,行級甚至

mvcc,sqlite的庫級併發確實顯得比較寒磣。但是鎖粒度越細,意味著維護鎖的成本越高,系統也會越複雜,因此sqlite的封鎖機制

要簡單很多,對資源的消耗也非常少。sqlite 3.7版本後,對併發控制做了優化,推出了wal日誌模式,可以實現讀寫併發,但同乙個

時刻仍然只能有乙個寫事務。由於sqlite的實現方式,sqlite只支援兩種隔離級別,序列化和讀未提交。讀未提交,就是讀全程不上鎖;序列化在事務開啟時上讀鎖,上鎖和釋放鎖同樣遵守兩階段鎖協議,在事務提交或回滾時才釋放鎖。

檔案鎖要說清楚sqlite鎖實現機制,首先要了解檔案鎖,因為sqlite所有鎖實現都是基於檔案鎖。對於linux系統,

檔案鎖主要包含兩類,協同鎖和強制鎖,協同鎖類似於互斥量,需要參與者都遵守遊戲規則,在操作檔案前,都先上鎖,

而強制鎖由os核心強制實行。協同鎖根據鎖粒度分為檔案級別和範圍級別。鎖檔案是最簡單的對檔案加鎖的方法,

每個需要加鎖的資料檔案都有乙個鎖檔案(lock file)。

當鎖檔案存在時,就認為該資料檔案已經被加鎖,別的程序不應該訪問。

當鎖不存在,程序就可以建立乙個鎖檔案,然後訪問相應的資料檔案。

只要建立鎖的過程是原子的,就能保證某一時刻只有乙個程序擁有該鎖,這種方法保證某一時刻只有乙個程序訪問檔案。

檔案鎖的弊端顯而易見,併發粒度太低。範圍鎖相對於檔案鎖,可以鎖檔案的一部分內容,並且有讀鎖和寫鎖。對於

同一部分內容,讀鎖可以共存,讀鎖和寫鎖互斥。posix標準提供介面fcntl()來實現。

鎖型別 

sqlite中的鎖正是利用了範圍鎖來實現併發控制的目的。sqlite中主要包含了4種鎖:

共享鎖(shared_lock)、保留鎖(reserved_lock)、未決鎖(pending_lock)和排它鎖(exclusive_lock),這4種

鎖定義了3個區域,其中共享鎖和排它鎖占用檔案相同的區域。具體而言,sqlite定義了檔案的以下區域為鎖檔案區域,由於

fcntl可以對不存在的檔案區域加鎖,因此 pending_byte定位在區域1g的地方,即使db檔案沒這麼大也不影響。

三種型別的鎖,分別在1g,1g+1,1g+2的偏移處,之所以shared_size長度是510,原因在於windows環境下,

lockfile()加鎖區域不能重疊(linux沒有這種問題),對於同乙個位元組上鎖會影響併發,

因此設定了乙個範圍,對shared_first—shared_first+ shared_size範圍內的隨機數進行加鎖,這樣可以減少衝突,保證高效的讀取檔案。

具體鎖類別和說明參見表1

鎖類別位元組範圍 說明

pending_byte

0x40000000

一種過渡鎖,讀事務獲取讀鎖,寫事務獲取寫鎖前,都需要獲取該鎖。

reserved_byte

0x40000001

表示執行緒要開始寫操作,某一時刻只能有乙個reserved lock,但是reserved鎖和shared鎖可以共存,而且可以對資料庫加新的shared鎖。

shared_lock

0x40000002-0x40000200

共享鎖,開啟事務時,都需要獲取該鎖

exclusive_lock

0x40000002-0x40000200

排它鎖

表1從各個鎖的作用來看,不免會疑問,為啥要加上reserved_lock和pending_lock兩種型別,直接通過共享鎖和排它鎖不就可以達到讀讀共享,讀寫互斥的目的了嗎。

這裡引入這reserved鎖的目的是為了提高併發。由於sqlite只有庫級排斥鎖(exclusive lock),如果寫事務一開始就上exclusive鎖,然後再進行實際的資料更新,

寫磁碟操作,這會使得併發性大大降低。而sqlite一旦得到資料庫的reserved鎖,就可以對快取中的資料進行修改,而與此同時,

其它程序可以繼續進行讀操作。直到真正需要寫磁碟時才對資料庫加exclusive鎖。pending鎖的作用主要是為了防止寫餓死的情況,寫事務獲取pending鎖後,新的讀事務

無法再進來,然後再加exclusive鎖,這樣寫事務獲取鎖的機率大大提高,讀寫事務的流程如下表2,狀態變遷圖如圖1。

型別 操作

鎖資訊 說明

讀事務begin

不持有鎖

select c1 from user where id=1

lock: pending(read)

lock:shared(read)

unlock:pending

獲取shared讀鎖前,需要先獲取pending共享鎖,

通過這種方式與寫事務互斥。

commit

unlock:shared

寫事務

begin

update c1=c1+1 where id=1

lock: pending(read)

lock:shared

unlock:pending

lock:reserved(write)

先獲取shared讀鎖,然後獲取reserved的排它鎖,阻止其它寫事務

commit

lock:pending(write)

lock:exclusive(write)

unlock: pending

unlock: exclusive(write)

獲取pending的排它鎖,阻止新的讀事務,最後上排它鎖,阻止所有讀事務,讀寫不能併發

pending鎖方式好處是,減少寫餓死的機率。

表2

圖1wal鎖型別

鎖類別位元組範圍 說明

讀事務(wal)

begin

select c1 from user where id=1

db檔案:

lock: pending(read)

lock:shared

unlock:pending

wal檔案:

lock:wal-read-lock(read)

除了獲取db檔案鎖,還需要獲取wal鎖,得到最新提交事務的位點。

若有事務再作檢查點,需要重試多次。

commit

unlock:shared-read-lock

unlock:shared

寫事務(wal)

begin

update c1=c1+1 where id=1

db檔案:

lock: pending-read

lock:shared(read)

unlock:pending

wal檔案:

lock:shared-read-lock[0]

lock:exclusive-write-lock 通過

exclusive-write-lock控制寫寫併發

由於不操作db檔案,因此不存在讀寫衝突,讀寫可以併發。

commit

wal檔案:

lock:shared-read-lock

unlock:shared-read-lock

unlock: exclusive-write-lock

db檔案:

unlock:shared

獲取shared-read-lock目的是為了獲取最新提交日誌的位點

檢查點操作 (wal)

wal檔案:

lock:exclusive-ckpt-lock

lock:exclusive-write-lock

unlock:exclusive-write-lock

unlock:exclusive-ckpt-lock

exclusive-ckpt-lock

保證只有乙個寫事務做檢查點;

exclusive-write-lock阻止讀事務。

表3除錯

sqlite通過幾個巨集定義可以列印語句執行的鎖資訊,方便大家了解語句執行中加了哪些鎖,什麼時候加的,什麼時候釋放的,以及如何處理鎖衝突。具體的巨集包括sqlite_lock_trace,sqlite_force_os_trace,和sqlite_debug,具體可以在**中檢視巨集定義的注釋。

gcc sqlite3.c -g -lpthread -ldl -fpic -shared -dsqlite_test -dsqlite_debug -dsqlite_lock_trace -dsqlite_force_os_trace -o libsqlite3.so
參考文件

python自帶sqlite 使用SQLite

python就內建了sqlite3,所以,在python中使用sqlite,不需要安裝任何東西,直接使用。在使用sqlite前,我們先要搞清楚幾個概念 表是資料庫中存放關係資料的集合,乙個資料庫裡面通常都包含多個表,比如學生的表,班級的表,學校的表,等等。表和表之間通過外來鍵關聯。要操作關聯式資料庫...

SQLite學習筆記

官方站點 從 的download頁面獲取 download.html sqlite amalgamation 3 6 22.zip是sqlite的windows下原始碼檔案 sqlite 3 6 22.zip sqlitedll 3 6 22.zip 在sqlite中,表示式 a between b...

SQLite學習筆記

官方站點 從 的download頁面獲取 download.html sqlite amalgamation 3 6 22.zip是sqlite的windows下原始碼檔案 sqlite 3 6 22.zip sqlitedll 3 6 22.zip 在sqlite中,表示式 a between b...