2012-10-24 66 views
1

我遇到問題,我想將7000行插入到SQLite數據庫中,但是當我到達第6000行時,我的應用程序崩潰,沒有錯誤。在將7000行插入SQLite數據庫時,應用程序崩潰

我使用了一個探查器,顯然問題是我的iPad上的RAM使用情況(當應用程序分配435MB的RAM時它崩潰)。

所以我的問題是如何在插入過程中管理內存? (是的,我需要在本地擁有這些數據,因爲我的應用程序需要以斷開模式工作)。

下面是我用在表中插入行的代碼:

-(void)MultiInsertFamille:(NSArray *)categories{ 
sqlite3_stmt *stmt=nil; 
sqlite3 *bdd; 

NSString *database = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"myBDD.sqlite"]; 
if (sqlite3_open([database UTF8String], &bdd) == SQLITE_OK) 
{ 
    sqlite3_exec(bdd, "BEGIN", 0, 0, 0); 
    const char *sqlstatement="insert into Famille values(?,?,?,?,?,?,?)"; 

    if(sqlite3_prepare_v2(bdd,sqlstatement , -1, &stmt, NULL)==SQLITE_OK) 
    { 
     int hasError= 0; 
     int i = 0; 
     for(NSString *path in categories) 
     { 
      i++; 
      NSString *nameFile = [[path componentsSeparatedByString: @"."] objectAtIndex:0]; 
      XMLParserFamille *fa = [[XMLParserFamille alloc] initXMLParserFamille:nameFile parseError:nil]; 
      FamilleData *fam = fa.famille; 
      [fa release]; 

      if (fam.champ_Recherche) 
       sqlite3_bind_text(stmt, 1, [fam.champ_Recherche cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT); 
      else 
       sqlite3_bind_text(stmt, 1, "NULL", -1, SQLITE_TRANSIENT); 

      NSString *pathImTh = @""; 
      for (Attribut *att in fam.Attributs) 
      { 
       if ([att.name isEqualToString:@"ProductThumbnail"]) 
       { 
        pathImTh = att.value; 
        break; 
       } 
      } 
      if (pathImTh) 
       sqlite3_bind_text(stmt, 2, [pathImTh cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT); 
      else 
       sqlite3_bind_text(stmt, 2, "NULL", -1, SQLITE_TRANSIENT); 

      if (fam.nom) 
       sqlite3_bind_text(stmt, 3, [fam.nom cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT); 
      else 
       sqlite3_bind_text(stmt, 3, "NULL", -1, SQLITE_TRANSIENT); 

      if (fam.ordre) 
       sqlite3_bind_int(stmt, 4, [fam.ordre intValue]); 
      else 
       sqlite3_bind_int(stmt, 4, 0); 

      if (fam.uid) 
       sqlite3_bind_text(stmt, 5, [fam.uid cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT); 
      else 
       sqlite3_bind_text(stmt, 5, "NULL", -1, SQLITE_TRANSIENT); 

      if (fam.uid_Categorie) 
       sqlite3_bind_text(stmt, 6, [fam.uid_Categorie cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_TRANSIENT); 
      else 
       sqlite3_bind_text(stmt, 6, "NULL", -1, SQLITE_TRANSIENT); 

      if (fam.xmlErrone) 
       sqlite3_bind_int(stmt, 7, [fam.xmlErrone intValue]); 
      else 
       sqlite3_bind_int(stmt, 7, 0); 

      if(sqlite3_step(stmt)==SQLITE_DONE) 
      { 
       NSLog(@"OK"); 
      } 
      else 
      { 
       NSLog(@"sqlite3_step error famille: '%s'", sqlite3_errmsg(bdd)); 
       hasError= 1; 
      } 
      sqlite3_reset(stmt); 
      if (i==5500) 
       break; 
     } 
     //if(hasError == 0) { 
     sqlite3_exec(bdd, "COMMIT", 0, 0, 0); 
     //} 
     //else { 
     // sqlite3_exec(bdd, "ROLLBACK", 0, 0, 0); 
     //} 
    } 
} 
sqlite3_close(bdd);} 
+0

你確定空字段應該有* string *''NULL''嗎?我猜你想用['sqlite3_bind_null'](http://www.sqlite.org/c3ref/bind_blob.html)來代替。 –

回答

0

在循環中可以創建很多臨時對象(例如字符串處理)。

您可以嘗試將自己的東西放入autorelease池塊,因此在每個循環結束時都會釋放臨時對象。

for(NSString *path in categories) { 
    @autoreleasepool { 
     your stuff here .. 
    } 
} 
+0

我有我的數據庫保存在RAM中的感覺(因爲當我提交RAM不是免費的),所以這釋放數據庫的對象? – Illuyankas

2

你可以嘗試做較小的事務,比如開始/提交每1000行。

類似的東西可能會有所幫助:

NSInteger rowsProcessed = 0; 
for(NSString *path in categories) 
{ 
    if (rowsProcessed == 0) 
    { 
    sqlite3_exec(bdd, "BEGIN", 0, 0, 0); 
    } 
    if (rowsProcessed++ > 1000) 
    { 
    sqlite3_exec(bdd, "COMMIT", 0, 0, 0); 
    rowsProcessed = 0; 
    } 

    ... 
    // your inserts here 
    ... 
} 
if (rowsProcessed != 0) 
{ 
    sqlite3_exec(bdd, "COMMIT", 0, 0, 0); 
} 

變通辦法不提交提交(可能會影響性能從而SQLite是添加如果刪除開始/完全提交隱性交易):

  • 如果您在開始時你的表是空的,你可以完全刪除begin/commit,並在錯誤的情況下最後從表中刪除所有行。
  • 如果你的表不是空的,但你仍然想要在出錯時刪除所有行,那麼你可以刪除begin/commit並添加一些列,當你插入這些行時會保留一些唯一的ID(一個唯一的ID插入此方法),以便在出現錯誤時,可以通過此ID刪除所有行。
+0

好的,謝謝我試試這個,我以後再回到你身邊。 – Illuyankas

+3

沒有明確的事務,SQLite會自動將每一個命令包裝到一個事務中,會導致可怕的性能。 –

+0

@CL。感謝您指出這一點,更新了我的答案,以解決該問題 –

相關問題