事務:
事務定義了一株sql命令的邊界,這組命令或者作為一個整體被全部執行,或者都不執行,稱為原子性原則。 事務的本質就是都執行,或者都不執行,而且是同時性的。
最具令人信服的是銀行轉賬過程。(詳情請百度orgoogle)。
事務的範圍:
事務的三個控制命令:begin 、 commit 、 rollback 。begin開始事務,如果沒有commit,則幾乎所有的操作都可以取消。commit提交事務後,執行所有的操作。rollback還原begin後的所有的操作。
當開始事務後,但是沒提交:
此時,可以看到,表foo裡沒有任何資料。
那麼rollback之後呢?看看:
可以看到,rollback之後,資料沒有發生任何變化,相對於事務開始前。
再看commit的功能:
值得注意的是,在SQLite中,,每句SQL語言自成事務,可自動認可。其可在遇到錯誤的命令的時候自動復原。即隱含交易。而且SQLite支援savepoint和release命令。
建立和啟動savepoint的命令的方法;
savepoint justincase ;
rollback [ transaction ] to justincase ;
再看:
這裡就復原到了預期的插入行了。
衝突解決:
違反約束可鞥導致事務結束。
SQLite的五種可能的沖入解決方案:replace,ignore,fail,abort,rollback。容錯範圍和敏感度依次增加,越來越嚴格。
replace:違反約束時,只是利用新的記錄代替違反約束的記錄,刪除原來違反約束的記錄,SQL繼續執行,不報錯。不會觸發觸發器。
ignore:繼續執行,違反約束的行的記錄不變,其前後都被修改。不報錯。
fail :直接在錯誤的記錄處終止,不恢複違反約束之前的修改的記錄,不復原。命令終止。
abort :約束違法時,恢複所有的命令做出的改變。是預設的解決辦法,SQL標準定義的行為。此時,這個衝突解決方案策略是最昂貴的,需要額外的工作。
rollback: 違反約束時,SQLite執行復原,終止當前的命令和整個事務。當前命令和之前的命令的改變都將會復原。最嚴格的衝突解決辦法。
衝突解決辦法在SQL命令中指定,也可以在表和索引的執行中執行。也就是說,衝突解決辦法可以在insert、update、create table、create index中指定。
衝突解決辦法在insert或者update中的文法形式:
insert or resolution into table (column_list ) values (value_list ) ;
update or resolution into table set (value_list ) where predicate ; 注意參考其他資料庫的merge和upset。
sql命令中的衝突解決辦法:
在表的定義中為單個欄位指定衝突解決辦法:
無法提交,是因為事務已經自動提前終止了。注意rollback的特點。
資料庫鎖:
SQLite中,鎖與事務關係密切。它採用粗粒度的鎖。當一個串連
當一個串連寫資料庫,其他的串連被鎖住,直到寫事務完成。
採用鎖逐步提升技術。SQLite的五種鎖狀態:未加鎖(unlocked)、共用鎖定(shared)、預留鎖(reserved)、未決鎖(pending)、獨佔鎖定(exclusive)。一個串連一種狀態,一種鎖。
最初未加鎖狀態,串連沒訪問資料庫;當串連資料庫時,或者事務已經begin時,還是未加鎖狀態。當從資料庫中讀資料時,進入共用狀態。多個串連可以保持多個共用鎖定,即多個串連可從同一個資料庫中讀資料。如果共用鎖定至少有一個沒釋放,那麼就不能寫資料。
一個串連寫資料的時候,先申請預留鎖,一個資料庫只能由一個預留鎖,此鎖可與共用鎖定共存。預留鎖不阻止其他串連對資料庫的讀和其他串連獲得對資料庫新的共用鎖定。這時候,預留鎖狀態時,開始進行寫操作,實在緩衝區進行的 , 並沒寫入到磁碟 ; 而當串連提交事務時,預留鎖上升為獨佔鎖定。 在提升預留鎖為獨佔鎖定的過程中,要先將預留鎖提升為未決鎖,獲得未決鎖後,其他串連不能再獲得新的共用鎖定,但已有的共用鎖定還是可以串連並且讀取資料庫的,同時在共用鎖定讀取資料庫的過程中,未決鎖一直在等待共用鎖定完成取並且釋放共用鎖定。
當所有的共用鎖定被釋放完畢後,擁有未決鎖的串連就可將其所提升為獨佔鎖定,此時對資料庫的修改開始,所有以前緩衝的修改將會被寫到資料庫檔案中。
死結:*******************
死結的情況比較少見,可以通過正確的事務類型來解決。先來瞭解下死結產生的一種情況:
假設的死結情況
執行順序 |
串連A |
串連B |
| 1 |
begin; |
|
| 2 |
|
begin; |
| 3 |
|
insert into foo values (xxx ); |
| 4 |
select * from foo; |
|
| 5 |
|
commit; |
| 6 |
|
error:db id locked |
| 7 |
insert into foo values (yyy); |
|
| 8 |
error:db is locked; |
|
兩串連都結束於死結。B串連先寫資料庫,產生了未決鎖,阻止其他串連的共用鎖定。這時A開始寫資料庫,但是無法獲得提升共用鎖定為預留鎖。其他的串連這時候都被拒絕了,既不能讀,更不能寫。此時,A、B各自的鎖都不放棄控制,將其他的操作阻止在資料庫外了,其他的進程不能操作資料庫了。
兩個串連最終都想寫資料庫,但他們最終沒放棄自己原來的鎖,共用鎖定導致錯誤。如果兩個串連以begin immediate / exclusive 開始,就無錯。