1. 程式人生 > >SQLite 檔案鎖和寫同步

SQLite 檔案鎖和寫同步

SQLite3 提供了一個新的鎖和同步機制來提高併發,減少死鎖。

SQLite3的鎖和同步有Pager Module(pager.c)負責處理。Pager Modue負責SQLite事務的ACID, 也提供快取功能。Pager Modue不需要知道BTree, 字元編碼, 索引的結構,  Pager Module用來管理Page, 一個Page對應一個DiskBlock, 大小一般是1024Byte。

1. SQLite3 資料庫的鎖狀態 
UNLOCKED
SHARED   共享鎖,可以讀,不能寫
RESERVED 保留鎖, 表示資料庫將被寫,但寫在快取中,還不能寫入資料庫,因為有其他連結持有共享鎖,還在讀資料。  一個數據庫只能有一個保留鎖, 保留鎖可以和共享鎖共存, 與PENDING鎖的不同之處在於還能獲得新的共享鎖,PENDING鎖被啟用時, 不能再獲得共享鎖。
PENDING(未決)此時,其他連結不再能獲取共享鎖,即,等待讀的連結退出,不接受新的連結來讀
EXCLUSIVE(排他),讀的連結都退出了,可以寫入資料庫了。

sqlite 鎖狀態很容易理解: 多個連結可以同時從一個paper中讀資料,但只允許一個連結往paper寫資料,而且在寫資料的時候不允許有其他連結讀資料,防止造成資料不一致。另外,連結持有共享鎖時,可以從paper中讀資料,持有保留鎖時可以往快取中寫資料和修改,如果想要把資料寫入paper中,就要限制新的連結獲取共享鎖、等待有共享鎖的連結執行完畢,此時稱為未決。

2.  回滾日誌檔案 
如果有更新資料庫操作, SQLite就會生成回滾日誌檔案, 以"-journal"的檔名結尾, 與資料庫檔案存放在同一目錄下。 如果多個數據庫同時工作, 每個資料庫都有自己的回滾日誌檔案, 並且還有一個master journal日誌檔案。master journal沒有資料, 只包含各個回滾日誌檔名。每個資料庫的回滾日誌檔案也會包含master journal檔名。
當訪問資料庫時發現有"hot journal"時, SQLite就會進行回滾工作, 回滾結束就刪除回滾日誌檔案。


處理"hot journal"
(1) 嘗試獲得SHARED LOCK, 如果失敗, 立即結束, 返回SQLITE_BUSY
(2) 檢查是否有"hot journal", 如果沒有立即返回, 否則繼續執行以下步驟
(3) 嘗試獲得PENDING LOCK, 然後EXCLUSIVE LOCK, 如果失敗, 表示其他程序正在做回滾, 釋放所有鎖, 關閉資料庫, 返回SQLITE_BUSY。 否則繼續執行
(4) 讀回滾日誌檔案, 回滾資料庫檔案
(5) 刪除回滾日誌檔案
(6) 刪除master journal 檔案
(7) 釋放PENDING LOCK和EXCLUSIVE LOCK, 但是保留SHARED LOCK


3. 寫資料庫檔案步驟 
(1) 獲得共享鎖
(2) 獲得RESERVED LOCK, 如果失敗, 返回SQLITE_BUSY, 否則繼續執行
(3) 生成回滾日誌檔案, 寫入磁碟, 等待寫完成繼續執行


如果是單個數據庫檔案
(4) 請求獲得PENDING LOCK
(5) 請求獲得EXCLUSIVE LOCK
(6) flush/fsync, 將更新寫入磁碟
(7) 刪除回滾日誌檔案
(8) 釋放EXCLUSIVE LOCK, PENDING LOCK, RESERVED LOCK, 獲得SHARED LOCK




如果是多個數據庫檔案事務
(4) 請求獲得PENDING LOCK 和EXCLUSIVE LOCK, 確保所有資料庫都獲得EXCLUSIVE LOCK
(5) 生成master journal檔案和每個資料庫的回滾日誌檔案
(6) flush/fsync, 將更新寫入磁碟
(7) 先刪除master journal 檔案, 再刪除所有的回滾日誌檔案
(8) 釋放所有資料庫上的EXCLUSIVE LOCK, PENDING LOCK


4. SQL事務 
預設SQLite autocommit=true
BEGIN TRANSACTION - COMMIT 命令使得SQLite不在autocommit下工作。當SQLite執行BEGIN命令時, 不會獲得任何鎖, 直到執行到第一個SELECT, 才獲得一個SHARED LOCK, 執行到UPDATE/INSERT/DELETE才獲得REVERSED LOCK, 當快取滿或者COMMIT時才請求獲得EXCLUSIVE LOCK。


COMMIT並非真正的將更新寫到磁碟, COMMIT使得SQLITE回到autocommit=true 模式, autocommit會負責將更新寫到磁碟。

5 寫同步

 初用sqlite3插入資料時,插入每條資料大概需要100ms左右。如果是批量匯入,可以引進事物提高速度。但是假設你的業務是每間隔幾秒插入幾條資料,顯然100ms是不能容許的。解決辦法是,在呼叫sqlite3_open函式後新增下面一行程式碼:
    sqlite3_exec(db, "PRAGMA synchronous = OFF; ", 0,0,0);
    上面的解決辦法貌似治標不治本,為什麼加上上面的程式碼行,速度會提高那麼多?網上解釋如下:
磁碟同步
1.如何設定:
PRAGMA synchronous = FULL; (2) 
PRAGMA synchronous = NORMAL; (1) 
PRAGMA synchronous = OFF; (0)
2.引數含義:
當synchronous設定為FULL (2), SQLite資料庫引擎在緊急時刻會暫停以確定資料已經寫入磁碟。這使系統崩潰或電源出問題時能確保資料庫在重起後不會損壞。FULL synchronous很安全但很慢。
當synchronous設定為NORMAL, SQLite資料庫引擎在大部分緊急時刻會暫停,但不像FULL模式下那麼頻繁。 NORMAL模式下有很小的機率(但不是不存在)發生電源故障導致資料庫損壞的情況。但實際上,在這種情況 下很可能你的硬碟已經不能使用,或者發生了其他的不可恢復的硬體錯誤。
設定為synchronous OFF (0)時,SQLite在傳遞資料給系統以後直接繼續而不暫停。若執行SQLite的應用程式崩潰, 資料不會損傷,但在系統崩潰或寫入資料時意外斷電的情況下資料庫可能會損壞。另一方面,在synchronous OFF時 一些操作可能會快50倍甚至更多。在SQLite 2中,預設值為NORMAL.而在3中修改為FULL。
3.建議:
如果有定期備份的機制,而且少量資料丟失可接受,用OFF。


     注意上面紅色加粗的字樣。總結:如果你的資料對安全性完整性等要求不是太高,可以採用設定為0的方法,畢竟只是“資料庫可能會損壞”,至於損壞機率為多大,筆者也暫不知曉。。。。。。還沒遇到過損壞,不知什麼時候才會發生。

相關推薦

SQLite 檔案同步

SQLite3 提供了一個新的鎖和同步機制來提高併發,減少死鎖。 SQLite3的鎖和同步有Pager Module(pager.c)負責處理。Pager Modue負責SQLite事務的ACID, 也提供快取功能。Pager Modue不需要知道BTree, 字元編碼,

shmget 共享記憶體 同步檔案一個程序,多個程序讀,讀同步,邊邊讀

首先,看看老大給我的任務:實現一個模組間的記憶體管理庫, 實現以下功能 1、該記憶體庫通訊的資料量不確定, 最大5Mbit/s  2、該記憶體庫用於模組間的資料互動 3、該記憶體庫只允許一個模組寫入, 但可多個模組讀取, 但需要各個讀取模組沒有任何相互干擾, 比如一個模組

深入Mysql機制(二)讀

深入Mysql鎖機制(二)讀鎖和寫鎖 這篇文章主要來介紹一下MySQL資料庫中的表級鎖。 本文提到的讀鎖和寫鎖都是MySQL資料庫的MyISAM引擎支援的表鎖的。而對於行級鎖的共享讀鎖和互斥寫鎖請閱讀MySQL中的共享鎖與排他鎖。我習慣在描述表鎖的時候按照讀寫來區分,在表

CSV檔案

把資料儲存到CSV CSV(Comma-Separated Values, 逗號分隔值)是儲存表哥資料的常用檔案格式 從零開始建立一個CSV檔案: import csv csvFile = open("../test.csv","w+") try:

生產者消費者 synchronized 互斥 lock同步

1  synchronized  package com.gc.test; /** * 生產者消費者問題 * 1 店員 * 2 生產者 * 3 消費者 * @author jiji * */ public class ProducetAndC

linux 多個使用者對一個檔案進行操作 檔案多路複用

①如果多個使用者對一個檔案進行操作的時候,如何解決,考慮用檔案鎖的形式和多路複用形式;1)檔案鎖找到一個函式flock()對檔案進行加鎖解鎖等操作,就是在使用前對檔案進行上鎖,在使用後對檔案進行解鎖,

MySQL中的讀

在資料庫的鎖機制中介紹過,資料的鎖主要用來保證資料的一致性的,資料庫的鎖從鎖定的粒度上可以分為表級鎖、行級鎖和頁級鎖。在我的部落格中重點介紹過MySQL資料庫的行級鎖。這篇文章主要來介紹一下MySQL資料庫中的表級鎖。 本文提到的讀鎖和寫鎖都是MySQL資料庫的My

同步與互斥,讀互斥

原文出處:http://blog.csdn.NET/u012884354/article/details/46691761 相交程序之間的關係主要有兩種,同步與互斥。所謂互斥,是指散佈在不同程序之間的若干程式片斷,當某個程序執行其中一個程式片段時,其它程序就不能執行它們之

sqlite記憶體資料庫檔案資料庫的同步

由於sqlite對多程序操作支援效果不太理想,在專案中,為了避免頻繁讀寫 檔案資料庫帶來的效能損耗,我們可以採用操作sqlite記憶體資料庫,並將記憶體資料庫定時同步到檔案資料庫中的方法。 實現思路如下: 1、建立檔案資料庫; 2、建立記憶體資料庫(檔案資料庫、記憶體資料庫

python-Lock線程同步互斥

() print b+ != val threading true pytho color 1 #!/usr/bin/python 2 #coding=utf-8 3 #線程間通信的同步與互斥操作-鎖 4 import threading 5 a=b=0 6

自旋,讀順序的實現原理

並且 保護 表達 min 返回 create creat rwlock ini 常用的同步原語鎖,到多核處理器時代鎖已經是必不可少的同步方式之一了。無論設計多優秀的多線程數據結構,都避不開有競爭的臨界區,此時高效的鎖顯得至關重要。鎖的顆粒度是框架/程序設計者所關註的,

MySQL數據庫同步之悲觀樂觀

我們 測試 http 鎖定 以及 再次 否則 即使 name 測試需要:本地開兩個測試窗口 悲觀鎖 悲觀鎖它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,在整個數據處理過程中,將數據處於鎖定狀態。悲觀鎖的實現,往往依靠數據庫提供的

python 學習第二十四天(同步遞迴

同步鎖 給一段程式碼加了同步鎖之後,在這段程式碼執行時只能有一個執行緒執行。 import time import threading def addNum(): global num #在每個執行緒中都獲取這個全域性變數 #num-=1

linux中的檔案(勸告性上強制性上)

上午在看UNP卷二這一節的時候及其想睡覺,就草草了事,夜晚沒有事情幹,就來找找部落格看看這兩個鎖到底是怎麼回事吧! 參考文章:https://www.ibm.com/developerworks/cn/linux/l-cn-filelock/index.html 背景知識:在早期的

linux下用互斥條件變數來實現讀

以下內容來源自UNP卷二的第八章 讀寫鎖的概念( the conception of read-write lock ) (1)只要沒有執行緒持有某個給定的讀寫鎖用於寫,那麼任意數目的執行緒可以持有該執行緒用於讀 (2)僅當沒有執行緒持有某個給定的讀寫鎖用於讀或用於寫,才能分配該

併發處理:一個死的例項執行緒監控

鎖 鎖是一個非常有用的工具,運用的場景非常多,因為他使用起來非常的簡單,而且易於理解。但是,鎖的問題就是很可能會出現一個非常壞的事情,就是一旦造成死鎖,就會導致執行緒得不到釋放,一旦死鎖的執行緒出現的太多,就會造成系統的不可用。 一、死鎖的例子 學習掌握一個概念,最好的方法就

ASP.NET 系統檔案操作XML配置讀

這裡將工作中用到的兩個工具分享一下:(1)、系統檔案操作工具(2)、XML讀寫配置檔案工具。 目錄 檔案操作工具 XML配置檔案讀寫 XML配置檔案讀取示例 檔案操作工具 using System; using System.Collections.Generic;

一分鐘學會讀csv檔案csv檔案(python實現)

  import csv with open('Python-Predict/Data/train.csv') as tra: rdr = csv.reader(tra) items = list(rdr) print("rdr:",rdr) print(items)

檔案記憶體對映mmap解決大檔案快速讀問題程序間共享記憶體

mmap函式主要用途有三個: 1、將一個普通檔案對映到記憶體中,通常在需要對檔案進行頻繁讀寫時使用,這樣用記憶體讀寫取代I/O讀寫,以獲得較高的效能; 2、將特殊檔案進行匿名記憶體對映,可以為關聯程序提供共享記憶體空間; 3、為無關聯的程序提供共享記憶體空間,一般也是將一個普通檔案對映到

多執行緒之同步執行緒停止

一.同步程式碼塊(同步鎖) 寫法: synchronized(鎖){ 上鎖的程式碼 } 當執行緒進入同步程式碼塊 會把鎖拿走 執行程式碼塊中的程式碼 程式碼執行完畢後 會把鎖還回去 如果執行緒遇到同步程式碼塊 發現沒有鎖 將進入等待(有鎖才可進) 鎖的注意:保證所有執行緒使用的是同一個鎖