2016-11-26 7 views
0

次のメソッドを使用してsqliteテーブルにデータを追加しています。 このメソッドを使用すると、最初にレコードが挿入され、その後に2番目のレコードを追加するために「データベースがロックされています」というメッセージが表示されます。 助けていただければ幸いです。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

こんにちは@ロブは、コードの一部を変更するためのヒントがありますが、(sqlite3_step(sqlStatement)== SQLITE_ROW)は必須ではありませんが、コードを変更する必要がある場所は他の場所です。 – puja

+0

他のコードを忘れてしまった接続を閉じる。 –

答えて

1

SQL文を実行するには2通りの方法があります。まず、必要に応じてsqlite3_stepを呼び出して、プレースホルダをバインドするsqlite3_bind_XXXを呼び出し、そして最後sqlite3_finalizeを呼び出し、sqlite3_prepare_v2のシーケンスを呼び出すことができます。次に、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の5番目のパラメータを使用すると、上記のように結果を解放する必要があります。

  2. sqlite3_XXXコール(特にsqlite3_open)の数値戻りコードを保存することをお勧めします。それはしばしば重要な診断ツールです。

  3. 私が開いて、データベースにこのようなすべての時間を閉じないでしょう。それは非効率的です。一般に、アプリケーションを起動するとデータベースを開き、アプリケーションを終了する前にデータベースを閉じます。しかし、それをいつも開いたり閉じたりするのは非効率です。

  4. 私はstringWithFormatでSQL文を構築助言しません。おそらくここでOKですが、一般的には?のプレースホルダを使用します。

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

    その後、これを準備するsqlite3_prepare_v2を呼び出してから、自分の価値観をバインドするsqlite3_bind_XXX機能を使用すると思います。このパターンは、ユーザーが指定したテキストを挿入するときに特に重要です。つまり、'という文字を持つユーザー指定の文字列に起因する問題を防ぐことができます。

    明らかに、このsqlite3_stmt道路を降りると、でなく、sqlite3_execとなります。

  5. はという文と一緒には意味をなさないので、SQLITE_ROWを返さないためです。 SELECTステートメントだけがSQLITE_ROWを返します。成功したINSERTステートメントはSQLITE_DONEを返します。 INSERTステートメントの場合は、sqlite3_stepに一度だけ電話してください。

  6. あなたのコードで例外処理を使用することをお勧めします。他のプログラミング環境から来た場合、これは逆説的に聞こえるかもしれませんが、Objective-Cでは、例外処理ではなく、エラー処理(NSErrorオブジェクトの回り込み)を実行時コードで使用しています。例外は、開発プロセス中にコードから削除する必要があります。開発プロセス中にそれらをキャッチする場合は、デバッガで例外ブレークポイントを使用します。しかし、プログラムで例外をキャッチすることは避けてください。あまり気付かないように、コードの深い問題を隠すことができます。

関連する問題