0

私のアプリケーションでは、ローカルのSqliteデータベースにいくつかのデータを保持しています。Sqliteを開き、すべて正常に動作するように挿入します。しかし、ASSERTION FAILUREメッセージで失敗した場合に、特定の行/レコードのデータを更新しようとすると。

* -[gss_databaseHandler updateRecord ::::]、/ Users / gss / Desktop / SalesPro copy / SalesPro /../ gss_databaseHandler.m:210でのアサーションの失敗

NSString *databasePath;
// Method to open a database, the database will be created if it doesn't exist
-(void)initDatabase
{
// Create a string containing the full path to the sqlite.db inside the documents folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
databasePath = [documentsDirectory stringByAppendingPathComponent:@"contact1"];

// Check to see if the database file already exists
bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];

// Open the database and store the handle as a data member
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
{
    // Create the database if it doesn't yet exists in the file system
    if (!databaseAlreadyExists)
    {
        // Create the contactList table
        const char *sqlStatement = "CREATE TABLE IF NOT EXISTS contactList (sapCustId TEXT, sapContactId TEXT, record_ID NUMERIC PRIMARY KEY, timestamp TEXT)";
        char *error;
        if (sqlite3_exec(databaseHandle, sqlStatement, NULL, NULL, &error) == SQLITE_OK)
        {
                NSLog(@"Database and tables created.");
        }
        else
        {
                NSLog(@"Error: in creating/opening database");
        }

    }
  }
}


- (void) updateRecord:(int)recordID:(NSString *)sapCustId:(NSString *)sapContactId:(NSString *)timestamp {

[self initDatabase];

sqlite3_stmt *updateStmt = nil;

    if(updateStmt == nil) {
        const char *sql_stmt = "update contactList Set sapCustId = ?, sapContactId = ?, timestamp = ? Where record_ID = ?";

     if(sqlite3_prepare_v2(databaseHandle, sql_stmt, -1, &updateStmt, NULL) != SQLITE_OK)
         NSAssert1(0, @"Error while creating update statement. '%s'", sqlite3_errmsg(databaseHandle));
    }

    sqlite3_bind_text(updateStmt, 0, [sapCustId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(updateStmt, 1, [sapContactId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(updateStmt, 2, recordID);
    sqlite3_bind_text(updateStmt, 3, [timestamp UTF8String], -1, SQLITE_TRANSIENT);

    if(SQLITE_DONE != sqlite3_step(updateStmt))
        NSAssert1(0, @"Error while updating. '%s'", sqlite3_errmsg(databaseHandle));

sqlite3_finalize(updateStmt);
sqlite3_close(databaseHandle);

//Reclaim all memory here.
[sapContactId release];
[sapCustId release];

}

plsヘルプ!..

4

2 に答える 2

1

だから、いくつかの考え:

  1. PrateekとLefterisが提案したbindように、SQLのフィールドの順序と一致するように、呼び出しの順序を変更する必要があります。また、ゼロではなく1のインデックスで始まります。sqlite3_bind呼び出しのインデックスが1から始まるのに対し、呼び出しのインデックスが0から始まるのはいつも奇妙だと思っていますsqlite3_columnが、それはまさにそれが機能する方法です。

  2. おそらく問題はありませんが、アサーションを実行する場合は、通常、最初に(a)正常に準備されたステートメントを完成させる必要があります。(b)データベースを閉じます。データベースを一貫性のない状態のままにしておくリスクを冒したくありません。

  3. おそらくここでリリースするべきではありませsapContactIdsapCustIdretainあなたは彼らの保持数を増やすために何もしなかったか、何もしなかったので、ここでそれらを解放することはおそらく賢明ではありません。静的アナライザーを介してコードを実行する場合(shift+ command+を押すBか、製品メニューから[分析]を選択)、間違いなくそこに提案/警告が表示されます。

  4. 公式のSQLiteAnIntroduction to the SQLite C / C ++ Interfaceで概説されているように、、、、、のシーケンスは完全openに正しいです。を呼び出す必要はありません。の目的は、以前に準備したものを再利用できるようにすることですが、ここではそれを行っていないため、ここでは不要であり、何も達成されません。prepare_v2stepfinalizeclosesqlite3_resetresetsqlite3_stmtreset

  5. コメントのある時点で、「データベースがロックされました」というエラーが発生したとのことです。上記の項目に対処しても問題が解決しない場合は、この問題のさまざまな原因が考えられるため、どこで問題が発生しているのかをお知らせください(SQLステートメントの実行open中は?)。prepare確かに、マルチスレッドのデータベース操作がこれを引き起こす可能性があります。このロックされたメッセージを受け取っている行を正確に示し、特に何かをしている場合に、他にどのようなデータベース操作(元の質問のコード以外)を行っているかを説明することで、これを診断するのに役立つ必要がありますバックグラウンドキュー/スレッド。

    「データベースロック」問題を解決する際の課題は、問題が常に「データベースロック」エラーが発生しているコードではなく、適切に処理できなかった以前のデータベース操作にあることです。技術的には、呼び出しに失敗するとsqlite3_finalize「データベースがロックされた」問題が発生する可能性がありますが、実際にはそうなることはめったにありません。prepare「データベースロック」エラーは通常、他の問題が原因で発生しますが、データベースを開いているときに発生しているのかstep、SQLステートメントを試行しているときに発生しているのかを知る必要があります。あなたは私たちが診断をさらに進めるためにどれを私たちに伝える必要があります。しかし、私が言ったように、問題は間違いなく他の/以前のデータベースの相互作用にあります、「データベースがロックされました」エラーの前。


元の質問のコードの書き直しに関する議論に興味がある場合は、以下を参照してください。

マイナーな提案ですが、呼び出しが失敗しinitDatabaseた場合にエラーメッセージをログに記録するようにメソッドを変更することをお勧めします。sqlite3_open

-(void)initDatabase
{
    // Create a string containing the full path to the sqlite.db inside the documents folder
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:@"contact1.sqlite"];
    
    // Check to see if the database file already exists
    bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
    
    // Open the database and store the handle as a data member
    if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
    {
        // Create the database if it doesn't yet exists in the file system
        if (!databaseAlreadyExists)
        {
            // Create the contactList table
            const char *sqlStatement = "CREATE TABLE IF NOT EXISTS contactList (sapCustId TEXT, sapContactId TEXT, record_ID NUMERIC PRIMARY KEY, timestamp TEXT)";
            char *error;
            if (sqlite3_exec(databaseHandle, sqlStatement, NULL, NULL, &error) == SQLITE_OK)
            {
                NSLog(@"Database and tables created.");
            }
            else
            {
                NSLog(@"%s: error creating table: %s", __FUNCTION__, sqlite3_errmsg(databaseHandle));
            }
        }
    }
    else
    {
        NSLog(@"%s: error opening database: %s", __FUNCTION__, sqlite3_errmsg(databaseHandle));
    }
}

第二に、あなたは見ますinsertRecord

  • 4つのbindステートメントを使用する順序を修正する必要があります。

  • 冗長なifステートメントを削除することもできます。

  • アサーションを使用する場合、またはデータベースの相互作用を行うメソッドの途中から戻る場合は、常に適切なクリーンアップを実行する必要があります。たとえば、準備が失敗したかどうかを確認します。閉じるだけですが、step失敗した場合は、必ずとをfinalize実行しcloseます。

  • releaseおそらく、これらの不適切なステートメントを取り除き、コード内の適切な場所に移動する必要があります。

  • メソッドのシグネチャを名前付きパラメータに変更する必要があります(コーディングガイドラインの「一般規則」セクションで、 Appleはメソッドキーワードに名前を付ける必要があると言っているためです。

したがって:

- (void) insertRecord:(int)recordID
            sapCustId:(NSString *)sapCustId
         sapContactId:(NSString *)sapContactId
            timestamp:(NSString *)timestamp
{
    [self initDatabase];
    
    sqlite3_stmt *statement = nil;
    
    const char *sql_stmt = "INSERT INTO contactList (sapCustId, sapContactId, timestamp, record_ID) VALUES (?, ?, ?, ?)";
    
    if(sqlite3_prepare_v2(databaseHandle, sql_stmt, -1, &statement, NULL) != SQLITE_OK)
    {
        NSLog(@"%s: insert prepare error: '%s'", __FUNCTION__, sqlite3_errmsg(databaseHandle));
        sqlite3_close(databaseHandle);
        NSAssert(0, @"insert prepare error");
    }
    
    sqlite3_bind_text(statement, 1, [sapCustId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(statement, 2, [sapContactId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(statement, 3, [timestamp UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(statement, 4, recordID);
    
    if (sqlite3_step(statement) != SQLITE_DONE)
    {
        NSLog(@"%s: insert step error: '%s'", __FUNCTION__, sqlite3_errmsg(databaseHandle));
        sqlite3_finalize(statement);
        sqlite3_close(databaseHandle);
        NSAssert(0, @"insert step error");
    }
    
    sqlite3_finalize(statement);
    sqlite3_close(databaseHandle);
}
于 2013-01-17T22:34:05.743 に答える
0

これを試して

sqlite3_reset がありません。番号は 1 から開始する必要があります

- (void) updateRecord:(int)recordID:(NSString *)sapCustId:(NSString *)sapContactId:(NSString *)timestamp {

[self initDatabase];

sqlite3_stmt *updateStmt = nil;

    if(updateStmt == nil) {
        const char *sql_stmt = "update contactList Set sapCustId = ?, sapContactId = ?, timestamp = ? Where record_ID = ?";

     if(sqlite3_prepare_v2(databaseHandle, sql_stmt, -1, &updateStmt, NULL) != SQLITE_OK)
         NSAssert1(0, @"Error while creating update statement. '%s'", sqlite3_errmsg(databaseHandle));
    }

    sqlite3_bind_text(updateStmt, 1, [sapCustId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(updateStmt, 2, [sapContactId UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(updateStmt, 3, [timestamp UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(updateStmt, 4, recordID);

    if(SQLITE_DONE != sqlite3_step(updateStmt))
        NSAssert1(0, @"Error while updating. '%s'", sqlite3_errmsg(databaseHandle));

sqlite3_reset(updateStmt);
sqlite3_finalize(updateStmt);
sqlite3_close(databaseHandle);

//Reclaim all memory here.
[sapContactId release];
[sapCustId release];

}

これがあなたに役立つことを願っています..

編集 :-

以前の関数を追加sqlite3_finalize();していないため、データベース ロック エラーが発生しています。

于 2013-01-17T10:06:56.983 に答える