《SQLite學習筆記(二)》要點:
本文介紹了SQLite學習筆記(二),希望對您有用。如果有疑問,可以聯系我們。
代碼下載
git clone git@github.com:mackyle/sqlite.git
SQLite的鎖
五種鎖狀態:
UNLOCKED:
文件沒有持有任何鎖,即當前數據庫不存在任何讀或寫的操作.其它的進程可以在該數據庫上執行任意的讀寫操作.此狀態為缺省狀態.
SHARED:
在此狀態下,該數據庫可以被讀取但是不能被寫入.在同一時刻可以有任意數量的進程在同一個數據庫上持有共享鎖,因此讀操作是并發的.換句話說,只要有一個或多個共享鎖處于活動狀態,就不再允許有數據庫文件寫入的操作存在.
RESERVED:
假如某個進程在將來的某一時刻打算在當前的數據庫中執行寫操作,然而此時只是從數據庫中讀取數據,那么我們就可以簡單的理解為數據庫文件此時已經擁有了保存鎖.當保存鎖處于活動狀態時,該數據庫只能有一個或多個共享鎖存在,即同一數據庫的同一時刻只能存在一個保存鎖和多個共享鎖.在Oracle中此類鎖被稱之為預寫鎖,不同的是Oracle中鎖的粒度可以細化到表甚至到行,因此該種鎖在Oracle中對并發的影響程序不像SQLite中這樣大.
PENDING:
PENDING鎖的意思是說,某個進程正打算在該數據庫上執行寫操作,然而此時該數據庫中卻存在很多共享鎖(讀操作),那么該寫操作就必須處于等待狀態,即等待所有共享鎖消失為止,與此同時,新的讀操作將不再被允許,以防止寫鎖饑餓的現象發生.在此等待期間,該數據庫文件的鎖狀態為PENDING,在比及所有共享鎖消失以后,PENDING鎖狀態的數據庫文件將在獲取排他鎖之后進入EXCLUSIVE狀態.
EXCLUSIVE:
在執行寫操作之前,該進程必需先獲取該數據庫的排他鎖.然而一旦擁有了排他鎖,任何其它鎖類型都不能與之共存.因此,為了最大化并發效率,SQLite將會最小化排他鎖被持有的時間總量.
鎖狀態轉換圖:
一個事務可以在UNLOCKED、RESERVED或EXCLUSIVE三種狀態下開始.默認情況下在UNLOCKED時開始.
白色框中的UNLOCKED、PENDING、SHARED和 RESERVED可以在一個數據庫的同一時刻存在.
從灰色的PENDING開始,事情就變得嚴格起來,意味著事務想得到排它鎖(EXCLUSIVE)(注意與白色框中的區別).
讀事務
db = open('foods.db')
db.exec('BEGIN')
db.exec('SELECT * FROM episodes')
db.exec('SELECT * FROM episodes')
db.exec('COMMIT')
db.close()
由于顯式地使用了BEGIN和COMMIT,兩個SELECT命令在一個事務下執行.第一個exec()執行時,連接處于SHARED,然后第二個exec()執行.當事務提交時,連接又從SHARED回到UNLOCKED狀態.
相應的狀態真正的變化過程為:UNLOCKED→PENDING(1)→PENDING、SHARED(2)→SHARED(6)→UNLOCKED
如果沒有BEGIN和COMMIT兩行,兩個SELECT都運行于自動提交狀態
相應的狀態真正的變化過程為:UNLOCKED→PENDING→SHARED→UNLOCKED→PENDING→SHARED→UNLOCKED
寫事務
類型 操作 鎖信息 說明 讀事務 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:SharedUnlock:PendingLock:Reserved(Write) 先獲取Shared讀鎖,然后獲取Reserved排它鎖,阻止其它寫事務 commit Lock:Pending(Write)Lock:Exclusive(Write)Unlock: PendingUnlock:Exclusive(Write) 獲取Pending的排它鎖,阻止新的讀事務,最后上排它鎖,阻止所有讀事務,讀寫不能并發Pending鎖方式好處是,減少寫餓死的幾率. WAL機制
WAL日志文件鎖
WAL日志鎖實質是鎖wal-index文件的區域,根據不同的鎖類型,將wal-index文件的不同區域劃定義成不同的鎖,主要有讀鎖,寫鎖,檢查點鎖.WAL模式下,最新的數據位于日志文件中,無論是讀事務還是寫事務都必要持有WAL_READ_LOCK的讀鎖,因為它們都必要獲取最新的事務點.因此,做檢查點時,可以通過對WAL_READ_LOCK位置(124-127)上鎖,來確定檢查點必要等待還是停止推進.同時我們也可以看到,對于DB文件,讀寫事務都只必要對DB文件上讀鎖,對于WAL日志文件,WAL_READ_LOCK和WAL_WRITE_LOCK位于不同的位置,讀寫相互不影響,所以讀寫不互斥.
類型 操作 鎖信息 說明 讀事務 begin 不持有鎖 select c1 from user where id =1 DB文件:Lock:Pending(Read)Lock:SharedUnlock:PendingWAL文件:Lock:WAL_READ_LOCK(Read) 除了獲取DB文件鎖,還必要獲取WAL鎖,得到最新提交事務的位點.若有事務再作檢查點,必要重試多次. commit Unlock:WAL_READ_LOCKUnlock:Shared 寫事務 begin 不持有鎖 Update c1=c1+1 where id =1 DB文件:Lock: Pending-ReadLock:Shared(Read)Unlock:PendingWAL文件:Lock:WAL_READ_LOCK(Read)Lock:WAL_WRITE_LOCK(Write) 通過EXCLUSIVE-WRITE-LOCK控制寫寫并發由于不操作DB文件,因此不存在讀寫沖突,讀寫可以并發. commit WAL文件:Lock:SHARED-READ-LOCKUnlock:WAL_READ_LOCK(Read)Unlock: WAL_WRITE_LOCK(Write)DB文件:Unlock:Shared 獲取SHARED-READ-LOCK目的是為了獲取最新提交日志的位點 checkpoint WAL文件:Lock:WAL_CKPT_LOCK(write)Lock:WAL_READ_LOCK(write)UnLock:WAL_READ_LOCKUnLock:WAL_CKPT_LOCK EXCLUSIVE-CKPT-LOCK保證只有一個寫事務做檢查點;WAL_READ_LOCK阻止讀寫事務.
維易PHP培訓學院每天發布《SQLite學習筆記(二)》等實戰技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養人才。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/9156.html