2012-10-24 67 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。感谢您指出这一点,更新了我的答案,以解决该问题 –

相关问题