2012-01-11 177 views
6

我有一個基於SQLite數據庫的系統。每個客戶端都有一個本地數據庫,偶爾會有更新從主服務器到達,只是一個很小的delta .db文件。任務是使用增量文件合併到本地數據庫,模式在兩者中都是相同的。分離SQLite數據庫時出錯 - 數據庫被鎖定

對於我的數據庫管理,我使用可以找到here的fmdb包裝。在主線程中,我保持與本地數據庫的連接處於打開狀態。增量文件到達後臺,我想在後臺進行合併,以避免任何用戶界面凍結,這可能會導致。

至於合併本身,我發現的唯一選擇是將增量數據庫附加到本地數據庫,然後插入/更新行,最後分離增量。這並不像我預期的那樣順暢。

代碼描述:

  • onDeltaGenerated方法在後臺線程中每當增量數據庫準備好被處理的(從服務器到達,並且被保存在可讀位置)調用。
  • deltaDBPath是文件系統中增量數據庫的絕對位置。
  • db變量引用打開FMDataBase連接。

代碼:

- (void)onDeltaGenerated:(NSNotification*)n { 
NSString* deltaDBPath = [[n userInfo] objectForKey:@"deltaPath"]; 
@synchronized(db) { 
    [db executeUpdate:@"ATTACH DATABASE ? AS delta", deltaDBPath]; 
    if ([db hadError]) { 
     NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]); 
    } else { 
     NSLog(@"Delta attached from %@", deltaDBPath); 
    } 
    [db beginTransaction]; 
    BOOL update1 = NO; 
    BOOL update2 = NO; 
    BOOL transaction = NO; 
    update1 = [db executeUpdate:@"INSERT OR REPLACE INTO equipment SELECT * FROM delta.equipment"]; 
    if (!update1) { 
     NSLog(@" *** ERROR *** update 1 failed!"); 
     NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]); 
    } 
    update2 = [db executeUpdate:@"INSERT OR REPLACE INTO equipmentExt SELECT * FROM delta.equipmentExt"]; 
    if (!update2) { 
     NSLog(@" *** ERROR *** update 2 failed!"); 
     NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]); 
    } 
    transaction = [db commit]; 
    if (!transaction) { 
     NSLog(@" *** ERROR *** transaction failed!"); 
     NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]); 
    } 
    [db executeUpdate:@"DETACH DATABASE delta"]; 
    if ([db hadError]) { 
     NSLog(@" ****ERROR*** %d: %@", [db lastErrorCode], [db lastErrorMessage]); 
    } else { 
     NSLog(@"Delta detached"); 
    } 
} 

}

後調用此方法的第一次,一切似乎是罰款,直到我試圖分離數據庫。當我嘗試這樣做,我得到以下錯誤:

2012-01-11 12:08:52.106 DBApp[1415:11507] Error calling sqlite3_step (1: SQL logic error or missing database) SQLITE_ERROR 
2012-01-11 12:08:52.107 DBApp[1415:11507] DB Query: DETACH delta 
2012-01-11 12:08:52.107 DBApp[1415:11507] ****ERROR*** 1: database delta is locked 

我也試圖相同,但沒有把插入到交易,結果是相同的。另一件事是刪除@synchronized子句,但也沒有運氣。我的猜測是,如果嘗試從後臺線程訪問本地數據庫連接時失敗,但是如何管理附加和插入?任何幫助讚賞。

編輯

我感動的代碼到主線程,所以現在分貝,僅由主線程訪問。問題依然存在。

EDIT2

好了,所以亂投醫後,我放棄了這個一會兒再回來時,第一個答案出現在這裏。令人驚訝的是,現在一切都好了,所以我的代碼必須是正確的。我懷疑這是鎖定文件的不同線程的問題,因爲我使用XCode,SQLiteDatabaseBrowser和我的應用程序來打開數據庫。儘管lsof顯示該文件未被鎖定,但我認爲這是錯誤的,無論是XCode還是SQLiteDatabaseBrowser都在鎖定它。我認爲這個問題已經解決了,並且從中吸取的教訓並不是過分強調這一點,而是在下一次更好地規劃調試。

+0

事務和executeUpdate方法都返回YES嗎? – Mark 2012-01-12 11:16:19

+0

是的,他們這樣做。此外,我檢查了是否有其他進程正在鎖定數據庫(我使用fuser),但事實並非如此。到目前爲止,我一直在測試SIM卡,但是現在我發現它在iPod Touch上也無法運行,因爲出現同樣的錯誤。 – lawicko 2012-01-12 13:11:39

+0

只需檢查:您的數據庫不存儲在NFS安裝的驅動器上,或者它是? – jogojapan 2012-03-02 04:54:47

回答

1

只需檢查 - NSLog(@"Delta attached from %@", deltaDBPath);是否成功打印,並且您描述的錯誤發生在那之後?


該行Error calling sqlite3_step (1: SQL logic error or missing database) SQLITE_ERROR可能是最有意思的一點。

經過一些Google搜索之後,出現的一個問題是數據庫文件可能無法寫入。 http://www.iphonedevsdk.com/forum/iphone-sdk-development/20142-problem-insert-fmdb.html

如果要更新主DB是應用程序的包內,你不允許修改它 - 你應該做一個拷貝到Documents或其他可寫目錄第一。


是錯誤實際發生時,你嘗試和分離,或當您嘗試進行INSERT OR REPLACE交易實際發生?

你應該在這些陳述之後再加上if ([db hadError]) {…以確保?

+0

嗨,感謝您花時間看這個。我更新了我的代碼,這樣我可以更容易地發現錯誤。此行發生錯誤:'[db executeUpdate:@「DETACH DATABASE delta」];'。數據庫是可寫的。我再次運行代碼,現在它工作正常!如果沒有出現,或者如果沒有人提供更具體的想法,我會再測試一次並接受你的答案。謝謝! – lawicko 2012-03-01 12:37:47

1

您是否已經

[db open]; 

其他地方?

+0

當然,我做到了。否則,它會在一開始就失敗。 – lawicko 2012-03-06 14:08:51

1

你確定你將所有查詢重置爲db嗎? 請確保您撥打sqlite3_reset(stmt)致電。

+0

不幸的是,我不能再訪問原始代碼,但正如我在編輯中所寫的那樣,它似乎是一次神奇消失的問題,我們沒有任何進一步的問題。但是,感謝回覆,當我再次收到數據庫鎖定錯誤時,我肯定會回來的! – lawicko 2013-04-17 14:47:23

0

下面是一個只是在我(你知道在哪裏): 我是徹底的(太多了,似乎)測試,同時建立一個新功能,需要一個額外的ATTACHed數據庫(在.NET中,由辦法)。 所以我

var i = query.ExecuteNonQuery("ATTACH DATABASE @FilePath AS `MergeDestination`;", fullPath); 
FakeCallThatDoesNothing() 
var i = query.ExecuteNonQuery("DETACH DATABASE `MergeDestination`;"); 

其中,appearently,沒有足夠的時間讓附着發生,並導致多頭部劃傷。