2016-11-26 90 views
0

我正在使用以下方法將數據添加到sqlite表。 使用此方法首先記錄獲取插入,然後添加第二個記錄我得到「數據庫被鎖定」。 任何幫助將不勝感激。如何處理Sqlite數據庫被鎖定在iOS?

-(BOOL)insertData:(float)old_otp old_generated_at:(NSString*)old_generated_at old_msp_delivery_time:(NSString*)old_msp_delivery_time old_valid_upto:(NSString*)old_valid_upto rc_profile_master_pm_id:(double)rc_profile_master_pm_id otp_validity:(BOOL)otp_validity 
{ 
    @try 
    { 
     NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; 
     NSString *documentsPath = [[documentsFolder stringByAppendingPathComponent:@"RCDB"] stringByAppendingPathExtension:@"sqlite"]; 

     BOOL success = [DBManager initDatabase]; 
     if(!success) 
     { 
      NSLog(@"Cannot locate database file '%@'.", documentsPath); 
     } 
     if(!(sqlite3_open([documentsPath UTF8String], &db) == SQLITE_OK)) 
     { 
      NSLog(@"An error has occurred."); 
     } 


     NSString *insertSQL = [NSString stringWithFormat: @"insert into rc_otp_log_details values(null,%f,'%@','%@','%@',%f,%d)",old_otp,old_generated_at,old_msp_delivery_time,old_valid_upto,rc_profile_master_pm_id,otp_validity]; 

     const char *sql = [insertSQL UTF8String]; 

     sqlite3_stmt *sqlStatement; 
     if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) == SQLITE_OK) 
     { 
      char *errMsg; 
      if (sqlite3_exec(db, sql, NULL, NULL, &errMsg) != SQLITE_OK) { 
       NSLog(@"Failed to create errMsg %s" ,errMsg); 
       sqlite3_finalize(sqlStatement); 
       sqlite3_close(db); 
       return false; 
      } 
      else 
      { 
       NSLog(@"inserted new"); 
       sqlite3_finalize(sqlStatement); 
       sqlite3_close(db); 
       return true; 
      } 
     } 
     else 
     { 
      NSLog(@"insert statement problem"); 
      sqlite3_finalize(sqlStatement); 
      sqlite3_close(db); 
      return true; 
     } 

     // 
     while (sqlite3_step(sqlStatement)==SQLITE_ROW) { 
      NSLog(@"SQLITE_ROW %%d,SQLITE_ROW"); 

     } 
     sqlite3_finalize(sqlStatement); 
     sqlite3_close(db); 
     return true; 
    } 
    @catch (NSException *exception) { 
     NSLog(@"An exception occured: %@", [exception reason]); 
     return false; 

    } 
    @finally { 
     return true; 
    } 
} 
+0

您是否在第一次插入時收到異常?這似乎是您不關閉數據庫連接的唯一方式,這可能會導致鎖定狀態。 –

+0

你好@Rob我可以提示哪裏改變部分代碼,我已經刪除while(sqlite3_step(sqlStatement)== SQLITE_ROW),因爲它不是必需的,但哪個是其他地方我需要更改代碼 – puja

+0

其他一些代碼忘記了關閉連接。 –

回答

1

有兩種執行SQL語句的方法。首先,您可以調用sqlite3_prepare_v2的順序,可選地呼叫sqlite3_bind_XXX來綁定佔位符,然後呼叫sqlite3_step,然後最後呼叫sqlite3_finalize。其次,你可以撥打sqlite3_exec

但是這段代碼正在做這兩個,這是不正確的。更糟糕的是,您已經開始sqlite3_prepare_v2進程,但停止一半嘗試執行sqlite3_exec,然後繼續第一個進程。

底線,不要同時準備sqlite3_stmt並致電sqlite3_exec。做一個或另一個。舉例來說,如果你要手動那樣建立你的SQL,你可以叫sqlite3_exec並用它做:

- (BOOL)insertData:(float)old_otp old_generated_at:(NSString*)old_generated_at old_msp_delivery_time:(NSString*)old_msp_delivery_time old_valid_upto:(NSString*)old_valid_upto rc_profile_master_pm_id:(double)rc_profile_master_pm_id otp_validity:(BOOL)otp_validity { 
    int rc; 
    NSString *documentsPath = ... 

    BOOL success = [DBManager initDatabase]; 
    if (!success) { 
     NSLog(@"Cannot locate database file '%@'.", documentsPath); 
    } 
    if ((rc = sqlite3_open([documentsPath UTF8String], &db)) != SQLITE_OK) { 
     NSLog(@"An error has occurred %ld.", (long)rc); 
     return false; 
    } 

    NSString *insertSQL = ... 

    const char *sql = [insertSQL UTF8String]; 

    if ((rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg) != SQLITE_OK) { 
     NSLog(@"Failed to create errMsg %s (%ld)", errMsg, (long)rc); 
     sqlite3_free(errMsg); 
    } 

    sqlite3_close(db); 

    return rc == SQLITE_OK; 
} 

幾個不相關的意見:

  1. 如果你使用sqlite3_exec的第五個參數,你真的應該釋放這個結果,如上所示。

  2. 我建議你一直保存sqlite3_XXX調用(尤其是sqlite3_open)的數字返回碼。它通常是一個重要的診斷工具。

  3. 我不會像這樣一直打開和關閉數據庫。這是低效的。通常我們在啓動應用程序時打開數據庫,然後在應用程序終止之前關閉數據庫。但像這樣不斷打開和關閉效率不高。

  4. 我不會建議使用stringWithFormat構建SQL語句。也許你可以在這裏,但一般來說,你會使用?佔位符,例如

    const char *sql = "insert into rc_otp_log_details values (null, ?, ?, ?, ?, ?, ?)"; 
    

    你會再調用sqlite3_prepare_v2準備這個,然後使用sqlite3_bind_XXX功能綁定你的價值觀。當插入用戶提供的文本時,這種模式尤爲重要,從而防止源自用戶提供的字符串的'字符(因此破壞了您手動構建的SQL)的問題。

    很明顯,如果你沿着這條路走下去,你會而不是也使用sqlite3_exec

  5. while (sqlite3_step(sqlStatement) == SQLITE_ROW) { ... }INSERT聲明結合是沒有意義的,因爲它永遠不會返回SQLITE_ROW。只有SELECT報表將返回SQLITE_ROW。成功的INSERT聲明將返回SQLITE_DONE。並且您只會撥打sqlite3_step一次以獲得INSERT聲明。

  6. 我會建議不要在你的代碼中使用異常處理。如果你來自其他編程環境,這可能聽起來似是而非,但在Objective-C中,我們在運行時代碼中使用了錯誤處理(傳遞大約NSError對象),而不是異常處理。在開發過程中應該從代碼中排除異常。如果您想在開發過程中捕獲它們,請在調試器中使用異常斷點。但是避免以編程方式捕獲異常,就好像你沒有注意到它一樣,你可以隱藏更深層次的代碼。