SQLite學習手冊(在線備份)

1、經常使用備份:

    下面的方法是比較簡單且經常使用的SQLite數據庫備份方式,見以下步驟:
    1). 使用SQLite API或Shell工具在源數據庫文件上加共享鎖。
    2). 使用Shell工具(cp或copy)拷貝數據庫文件到備份目錄。
    3). 解除數據庫文件上的共享鎖。
    以上3個步驟能夠應用於大多數場景,並且速度也比較快,然而卻存在必定的剛性缺陷,如:
    1). 全部打算在源數據庫上執行寫操做的鏈接都不得不被掛起,直到整個拷貝過程結束並釋放文件共享鎖。
    2). 不能拷貝數據到in-memory數據庫。
    3). 在拷貝過程當中,一旦備份數據庫所在的主機出現任何突發故障,備份數據庫可能會被破壞。
    在SQLite中提供了一組用於在線數據庫備份的APIs函數(C接口),能夠很好的解決上述方法存在的不足。經過該組函數,能夠將源數據庫中的內容拷貝到另外一個數據庫,同時覆蓋目標數據庫中的數據。整個拷貝過程能夠以增量的方式完成,在此狀況下,源數據庫也不須要在整個拷貝過程當中都被加鎖,而只是在真正讀取數據時加共享鎖。這樣,其它的用戶在訪問源數據庫時就不會被掛起。
    
2、在線備份APIs簡介:

    SQLite提供瞭如下3個APIs函數用於完成此操做,這裏僅僅給出它們的基本用法,至於使用細節能夠參考SQLite官方網站"APIs Reference"(http://www.sqlite.org/c3ref/backup_finish.html)。
    1). 函數sqlite3_backup_init()用於建立sqlite3_backup對象,該對象將做爲本次拷貝操做的句柄傳給其他兩個函數。
    2). 函數sqlite3_backup_step()用於數據拷貝,若是該函數的第二個參數爲-1,那麼整個拷貝過程都將在該函數的一次調用中完成。
    3). 函數sqlite3_backup_finish()用於釋放sqlite3_backup_init()函數申請的資源,以免資源泄露。
    在整個拷貝過程當中若是出現任何錯誤,咱們均可以經過調用目的數據庫鏈接的sqlite3_errcode()函數來獲取具體的錯誤碼。此外,若是sqlite3_backup_step()調用失敗,因爲sqlite3_backup_finish()函數並不會修改當前鏈接的錯誤碼,所以咱們能夠在調用sqlite3_backup_finish()以後再獲取錯誤碼,從而在代碼中減小了一次錯誤處理。見以下代碼示例(來自SQLite官網): html

複製代碼
 1 /*  2 ** This function is used to load the contents of a database file on disk  3 ** into the "main" database of open database connection pInMemory, or  4 ** to save the current contents of the database opened by pInMemory into  5 ** a database file on disk. pInMemory is probably an in-memory database,  6 ** but this function will also work fine if it is not.  7 **  8 ** Parameter zFilename points to a nul-terminated string containing the  9 ** name of the database file on disk to load from or save to. If parameter 10 ** isSave is non-zero, then the contents of the file zFilename are 11 ** overwritten with the contents of the database opened by pInMemory. If 12 ** parameter isSave is zero, then the contents of the database opened by 13 ** pInMemory are replaced by data loaded from the file zFilename. 14 ** 15 ** If the operation is successful, SQLITE_OK is returned. Otherwise, if 16 ** an error occurs, an SQLite error code is returned. 17 */ 18 int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave){ 19 int rc; /* Function return code */ 20 sqlite3 *pFile; /* Database connection opened on zFilename */ 21 sqlite3_backup *pBackup; /* Backup object used to copy data */ 22 sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */ 23 sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */ 24 25 /* Open the database file identified by zFilename. Exit early if this fails 26  ** for any reason. */ 27 rc = sqlite3_open(zFilename, &pFile); 28 if( rc==SQLITE_OK ){ 29 30 /* If this is a 'load' operation (isSave==0), then data is copied 31  ** from the database file just opened to database pInMemory. 32  ** Otherwise, if this is a 'save' operation (isSave==1), then data 33  ** is copied from pInMemory to pFile. Set the variables pFrom and 34  ** pTo accordingly. */ 35 pFrom = (isSave ? pInMemory : pFile); 36 pTo   = (isSave ? pFile     : pInMemory); 37 38 /* Set up the backup procedure to copy from the "main" database of 39  ** connection pFile to the main database of connection pInMemory. 40  ** If something goes wrong, pBackup will be set to NULL and an error 41  ** code and message left in connection pTo. 42  ** 43  ** If the backup object is successfully created, call backup_step() 44  ** to copy data from pFile to pInMemory. Then call backup_finish() 45  ** to release resources associated with the pBackup object. If an 46  ** error occurred, then an error code and message will be left in 47  ** connection pTo. If no error occurred, then the error code belonging 48  ** to pTo is set to SQLITE_OK. 49 */ 50 pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main"); 51 if( pBackup ){ 52 (void)sqlite3_backup_step(pBackup, -1); 53 (void)sqlite3_backup_finish(pBackup); 54 } 55 rc = sqlite3_errcode(pTo); 56 } 57 58 /* Close the database connection opened on database file zFilename 59  ** and return the result of this function. */ 60 (void)sqlite3_close(pFile); 61 return rc; 62 }
複製代碼

    
3、高級應用技巧:
    
    在上面的例子中,咱們是經過sqlite3_backup_step()函數的一次調用完成了整個拷貝過程。該實現方式仍然存在以前說過的掛起其它寫訪問鏈接的問題,爲了解決該問題,這裏咱們將繼續介紹另一種更高級的實現方式--分片拷貝,其實現步驟以下:
    1). 函數sqlite3_backup_init()用於建立sqlite3_backup對象,該對象將做爲本次拷貝操做的句柄傳給其他兩個函數。
    2). 函數sqlite3_backup_step()被調用用於拷貝數據,和以前方法不一樣的是,該函數的第二個參數再也不是-1,而是一個普通的正整數,表示每次調用將會拷貝的頁面數量,如5。
    3). 若是在函數sqlite3_backup_step()調用結束後,仍然有更多的頁面須要被拷貝,那麼咱們將主動休眠250ms,而後再重複步驟2).
    4). 函數sqlite3_backup_finish()用於釋放sqlite3_backup_init()函數申請的資源,以免資源泄露。
    在上述步驟3)中咱們主動休眠250ms,此期間,該拷貝操做不會在源數據庫上持有任何讀鎖,這樣其它的數據庫鏈接在進行寫操做時亦將不會被掛起。然而在休眠期間,若是另一個線程或進程對源數據庫進行了寫操做,SQLite將會檢測到該事件的發生,從而在下一次調用sqlite3_backup_step()函數時從新開始整個拷貝過程。惟一的例外是,若是源數據庫不是in-memory數據庫,同時寫操做是在與拷貝操做同一個進程內完成,而且在操做時使用的也是同一個數據庫鏈接句柄,那麼目的數據庫中數據也將被此操做同時自動修改。在下一次調用sqlite3_backup_step()時,也將不會有任何影響發生。  
    事實上,在SQLite中仍然提供了另外兩個輔助性函數backup_remaining()backup_pagecount(),其中前者將返回在當前備份操做中還有多少頁面須要被拷貝,然後者將返回本次操做總共須要拷貝的頁面數量。顯而易見的是,經過這兩個函數的返回結果,咱們能夠實時顯示本次備份操做的總體進度,計算公式以下:
    Completion = 100% * (pagecount() - remaining()) / pagecount() 
    見如下代碼示例(來自SQLite官網): sql

複製代碼
 1 /*  2 ** Perform an online backup of database pDb to the database file named  3 ** by zFilename. This function copies 5 database pages from pDb to  4 ** zFilename, then unlocks pDb and sleeps for 250 ms, then repeats the  5 ** process until the entire database is backed up.  6 **  7 ** The third argument passed to this function must be a pointer to a progress  8 ** function. After each set of 5 pages is backed up, the progress function  9 ** is invoked with two integer parameters: the number of pages left to 10 ** copy, and the total number of pages in the source file. This information 11 ** may be used, for example, to update a GUI progress bar. 12 ** 13 ** While this function is running, another thread may use the database pDb, or 14 ** another process may access the underlying database file via a separate 15 ** connection. 16 ** 17 ** If the backup process is successfully completed, SQLITE_OK is returned. 18 ** Otherwise, if an error occurs, an SQLite error code is returned. 19 */ 20 int backupDb( 21 sqlite3 *pDb, /* Database to back up */ 22 const char *zFilename, /* Name of file to back up to */ 23 void(*xProgress)(int, int) /* Progress function to invoke */ 24 ){ 25 int rc; /* Function return code */ 26 sqlite3 *pFile; /* Database connection opened on zFilename */ 27 sqlite3_backup *pBackup; /* Backup handle used to copy data */ 28 29 /* Open the database file identified by zFilename. */ 30 rc = sqlite3_open(zFilename, &pFile); 31 if( rc==SQLITE_OK ){ 32 33 /* Open the sqlite3_backup object used to accomplish the transfer */ 34 pBackup = sqlite3_backup_init(pFile, "main", pDb, "main"); 35 if( pBackup ){ 36 37 /* Each iteration of this loop copies 5 database pages from database 38  ** pDb to the backup database. If the return value of backup_step() 39  ** indicates that there are still further pages to copy, sleep for 40  ** 250 ms before repeating. */ 41 do { 42 rc = sqlite3_backup_step(pBackup, 5); 43 xProgress( 44 sqlite3_backup_remaining(pBackup), 45 sqlite3_backup_pagecount(pBackup) 46 ); 47 if( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ 48 sqlite3_sleep(250); 49 } 50 } while( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED ); 51 52 /* Release resources allocated by backup_init(). */ 53 (void)sqlite3_backup_finish(pBackup); 54 } 55 rc = sqlite3_errcode(pFile); 56 } 57 58 /* Close the database connection opened on database file zFilename 59  ** and return the result of this function. */ 60 (void)sqlite3_close(pFile); 61 return rc; 62 }
複製代碼
相關文章
相關標籤/搜索