SQLite入門與分析 二 設計與概念 續

2021-06-21 23:20:59 字數 3586 閱讀 6662

寫在前面:本節討論事務,事務是dbms最核心的技術之一.在計算機科學史上,有三位科學家因在資料庫領域的成就而獲acm圖靈獎,而其中之一jim gray(曾任職微軟)就是因為在事務處理方面的成就而獲得這一殊榮,正是因為他,才使得oltp系統在隨後直到今天大行其道.關於事務處理技術,涉及到很多,隨便就能寫一本書.在這裡我只討論sqlite事務實現的一些原理,sqlite的事務實現與大型通用的dbms相比,其實現比較簡單.這些內容可能比較偏於理論,但卻不難,也是理解其它內容的基礎.好了,下面開始第二節---事務.

2、    事務(transaction)

2.1、事務的週期(transaction lifecycles)

程式與事務之間有兩件事值得注意:

(1)    哪些物件在事務下執行——這直接與api有關。

(2)    事務的生命週期,即什麼時候開始,什麼時候結束以及它在什麼時候開始影響別的連線(這點對於併發性很重要)——這涉及到sqlite的具體實現。

乙個連線(connection)可以包含多個(statement),而且每個連線有乙個與資料庫關聯的b-tree和乙個pager。pager在連線中起著很重要的作用,因為它管理事務、鎖、記憶體快取以及負責崩潰恢復(crash recovery)。當你進行資料庫寫操作時,記住最重要的一件事:在任何時候,只在乙個事務下執行乙個連線。這些回答了第乙個問題。

一般來說,乙個事務的生命和statement差不多,你也可以手動結束它。預設情況下,事務自動提交,當然你也可以通過begin..commit手動提交。接下來就是鎖的問題。

2.2、鎖的狀態(lock states)

鎖對於實現併發訪問很重要,而對於大型通用的dbms,鎖的實現也十分複雜,而sqlite相對較簡單。通常情況下,它的持續時間和事務一致。乙個事務開始,它會先加鎖,事務結束,釋放鎖。但是系統在事務沒有結束的情況下崩潰,那麼下乙個訪問資料庫的連線會處理這種情況。

在sqlite中有5種不同狀態的鎖,連線(connection)任何時候都處於其中的乙個狀態。下圖顯示了相應的狀態以及鎖的生命週期。

關於這個圖有以下幾點值得注意:

(1)    乙個事務可以在unlocked,reserved或exclusive三種狀態下開始。預設情況下在unlocked時開始。

(2)    白色框中的unlocked, pending, shared和 reserved可以在乙個資料庫的同一時存在。

(3)    從灰色的pending開始,事情就變得嚴格起來,意味著事務想得到排斥鎖(exclusive)(注意與白色框中的區別)。

雖然鎖有這麼多狀態,但是從體質上來說,只有兩種情況:讀事務和寫事務。

2.3、讀事務(read transactions)

我們先來看看select語句執行時鎖的狀態變化過程,非常簡單:乙個連線執行select語句,觸發乙個事務,從unlocked到shared,當事務commit時,又回到unlocked,就這麼簡單。

考慮下面的例子(為了簡單,這裡用了偽碼):

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()執行時,connection處於shared,然後第二個exec()執行,當事務提交時,connection又從shared回到unlocked狀態,如下:

unlocked→pending→shared→unlocked

如果沒有begin和commit兩行時如下:

unlocked→pending→shared→unlocked→pending→ shared→unlocked

2.4、寫事務(write transactions)

下面我們來考慮寫資料庫,比如update。和讀事務一樣,它也會經歷unlocked→pending→shared,但接下來卻是灰色的pending,

2.4.1、the reserved states

當乙個連線(connection)向資料庫寫資料時,從shared狀態變為reserved狀態,如果它得到reserved鎖,也就意味著它已經準備好進行寫操作了。即使它沒有把修改寫入資料庫,也可以把修改儲存到位於pager中快取中(page cache)。

當乙個連線進入reserved狀態,pager就開始初始化恢復日誌(rollback journal)。在reserved狀態下,pager管理著三種頁面:

(1)    modified pages:包含被b-樹修改的記錄,位於page cache中。

(2)    unmodified pages:包含沒有被b-tree修改的記錄。

(3)    journal pages:這是修改頁面以前的版本,這些並不儲存在page cache中,而是在b-tree修改頁面之前寫入日誌。

page cache非常重要,正是因為它的存在,乙個處於reserved狀態的連線可以真正的開始工作,而不會干擾其它的(讀)連線。所以,sqlite可以高效的處理在同一時刻的多個讀連線和乙個寫連線。

2.4.2 、the pending states

當乙個連線完成修改,就真正開始提交事務,執行該過程的pager進入exclusive狀態。從reserved狀態,pager試著獲取pending鎖,一旦得到,就獨佔它,不允許任何其它連線獲得pending鎖(pending is a gateway lock)。既然寫操作持有pending鎖,其它任何連線都不能從unlocked狀態進入shared狀態,即沒有任何連線可以進入資料(no new readers, no new writers)。只有那些已經處於shared狀態的連線可以繼續工作。而處於pending狀態的writer會一直等到所有這些連線釋放它們的鎖,然後對資料庫加excusive鎖,進入exclusive狀態,獨佔資料庫(討論到這裡,對sqlite的加鎖機制應該比較清晰了)。

2.4.3、the exclusive state

在exclusive狀態下,主要的工作是把修改的頁面從page cache寫入資料庫檔案,這是真正進行寫操作的地方。

在pager寫入modified pages之前,它還得先做一件事:寫日誌。它檢查是否所有的日誌都寫入了磁碟,而這些通常位於操作的緩衝區中,所以pager得告訴os把所有的檔案寫入磁碟,這是由程式synchronous(通過呼叫os的相應的api實現)完成的。

日誌是資料庫進行恢復的惟一方法,所以日誌對於dbms非常重要。如果日誌頁面沒有完全寫入磁碟而發生崩潰,資料庫就不能恢復到它原來的狀態,此時資料庫就處於不一致狀態。日誌寫入完成後,pager就把所有的modified pages寫入資料庫檔案。接下來就取決於事務提交的模式,如果是自動提交,那麼pager清理日誌,page cache,然後由exclusive進入unlocked。如果是手動提交,那麼pager繼續持有exclusive鎖和儲存日誌,直到commit或者rollback。

總之,從效能方面來說,程序占有排斥鎖的時間應該盡可能的短,所以dbms通常都是在真正寫檔案時才會占有排斥鎖,這樣能大大提高併發效能。

SQLite入門與分析 二 設計與概念 續

寫在前面 本節討論事務,事務是dbms最核心的技術之一.在計算機科學史上,有三位科學家因在資料庫領域的成就而獲acm圖靈獎,而其中之一jim gray 曾任職微軟 就是因為在事務處理方面的成就而獲得這一殊榮,正是因為他,才使得oltp系統在隨後直到今天大行其道.關於事務處理技術,涉及到很多,隨便就能...

SQLite入門與分析 二 設計與概念 續

寫在前面 本節討論事務,事務是dbms最核心的技術之一.在計算機科學史上,有三位科學家因在資料庫領域的成就而獲acm圖靈獎,而其中之一jim gray 曾任職微軟 就是因為在事務處理方面的成就而獲得這一殊榮,正是因為他,才使得oltp系統在隨後直到今天大行其道.關於事務處理技術,涉及到很多,隨便就能...

SQLite入門與分析 二 設計與概念 續

寫在前面 本節討論事務,事務是dbms最核心的技術之一.在計算機科學史上,有三位科學家因在資料庫領域的成就而獲acm圖靈獎,而其中之一jim gray 曾任職微軟 就是因為在事務處理方面的成就而獲得這一殊榮,正是因為他,才使得oltp系統在隨後直到今天大行其道.關於事務處理技術,涉及到很多,隨便就能...