SQLite教程(九):在线备份
一、常用备份:
下面的方法是比较简单且常用的SQLite数据库备份方式,见如下步骤:
1).使用SQLiteAPI或Shell工具在源数据库文件上加共享锁。
2).使用Shell工具(cp或copy)拷贝数据库文件到备份目录。
3).解除数据库文件上的共享锁。
以上3个步骤可以应用于大多数场景,而且速度也比较快,然而却存在一定的刚性缺陷,如:
1).所有打算在源数据库上执行写操作的连接都不得不被挂起,直到整个拷贝过程结束并释放文件共享锁。
2).不能拷贝数据到in-memory数据库。
3).在拷贝过程中,一旦备份数据库所在的主机出现任何突发故障,备份数据库可能会被破坏。
在SQLite中提供了一组用于在线数据库备份的APIs函数(C接口),可以很好的解决上述方法存在的不足。通过该组函数,可以将源数据库中的内容拷贝到另一个数据库,同时覆盖目标数据库中的数据。整个拷贝过程可以以增量的方式完成,在此情况下,源数据库也不需要在整个拷贝过程中都被加锁,而只是在真正读取数据时加共享锁。这样,其它的用户在访问源数据库时就不会被挂起。
二、在线备份APIs简介:
SQLite提供了以下3个APIs函数用于完成此操作,这里仅仅给出它们的基本用法,至于使用细节可以参考SQLite官方网站"APIsReference"(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官网):
/* **Thisfunctionisusedtoloadthecontentsofadatabasefileondisk **intothe"main"databaseofopendatabaseconnectionpInMemory,or **tosavethecurrentcontentsofthedatabaseopenedbypInMemoryinto **adatabasefileondisk.pInMemoryisprobablyanin-memorydatabase, **butthisfunctionwillalsoworkfineifitisnot. ** **ParameterzFilenamepointstoanul-terminatedstringcontainingthe **nameofthedatabasefileondisktoloadfromorsaveto.Ifparameter **isSaveisnon-zero,thenthecontentsofthefilezFilenameare **overwrittenwiththecontentsofthedatabaseopenedbypInMemory.If **parameterisSaveiszero,thenthecontentsofthedatabaseopenedby **pInMemoryarereplacedbydataloadedfromthefilezFilename. ** **Iftheoperationissuccessful,SQLITE_OKisreturned.Otherwise,if **anerroroccurs,anSQLiteerrorcodeisreturned. */ intloadOrSaveDb(sqlite3*pInMemory,constchar*zFilename,intisSave){ intrc; /*Functionreturncode*/ sqlite3*pFile; /*DatabaseconnectionopenedonzFilename*/ sqlite3_backup*pBackup; /*Backupobjectusedtocopydata*/ sqlite3*pTo; /*Databasetocopyto(pFileorpInMemory)*/ sqlite3*pFrom; /*Databasetocopyfrom(pFileorpInMemory)*/
/*OpenthedatabasefileidentifiedbyzFilename.Exitearlyifthisfails **foranyreason.*/ rc=sqlite3_open(zFilename,&pFile); if(rc==SQLITE_OK){
/*Ifthisisa'load'operation(isSave==0),thendataiscopied **fromthedatabasefilejustopenedtodatabasepInMemory. **Otherwise,ifthisisa'save'operation(isSave==1),thendata **iscopiedfrompInMemorytopFile. SetthevariablespFromand **pToaccordingly.*/ pFrom=(isSave?pInMemory:pFile); pTo =(isSave?pFile :pInMemory);
/*Setupthebackupproceduretocopyfromthe"main"databaseof **connectionpFiletothemaindatabaseofconnectionpInMemory. **Ifsomethinggoeswrong,pBackupwillbesettoNULLandanerror **codeand messageleftinconnectionpTo. ** **Ifthebackupobjectissuccessfullycreated,callbackup_step() **tocopydatafrompFiletopInMemory.Thencallbackup_finish() **toreleaseresourcesassociatedwiththepBackupobject. Ifan **erroroccurred,then anerrorcodeandmessagewillbeleftin **connectionpTo.Ifnoerroroccurred,thentheerrorcodebelonging **topToissettoSQLITE_OK. */ pBackup=sqlite3_backup_init(pTo,"main",pFrom,"main"); if(pBackup){ (void)sqlite3_backup_step(pBackup,-1); (void)sqlite3_backup_finish(pBackup); } rc=sqlite3_errcode(pTo); }
/*ClosethedatabaseconnectionopenedondatabasefilezFilename **andreturntheresultofthisfunction.*/ (void)sqlite3_close(pFile); returnrc; }