0

私のアプリケーションはSQLiteデータベースを使用して連絡先の特定のデータを保存します。たとえば(record_ID、timestampなど)このメソッドを使用して特定の値でSQLITEレコードを更新しようとしています。

データベースを初期化した後、私はこのメソッドを呼び出していました。1つのレコードのみが更新されます。更新するたびにこのメソッドを呼び出しても。

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


static sqlite3_stmt *updateStmt = nil;

    if(updateStmt == nil) {
        NSString *sql = [NSString stringWithFormat:@"update contactList set sapCustId = \"%@\", sapContactId = \"%@\", timestamp = \"%@\" Where record_ID = \"%d\"", sapCustId, sapContactId, timestamp, recordID];

        const char *sql_stmt = [sql UTF8String];

        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_reset(updateStmt);
sqlite3_close(databaseHandle);

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

}

私に知らせてください、それを解決する方法は?

4

2 に答える 2

1

重要な問題は、コードがupdateStmt1回だけビルドされていることです。これは、staticであり、そうでないかどうかを確認しているためですnil。したがって、最初のSQLステートメントは作成されていますが、残りは作成されていません。最も簡単な修正は、static修飾子とif(updateStmt == nil) ...ロジックを削除するだけで、レースに参加する必要があります。また、必ず。に置き換えてsqlite3_resetくださいsqlite3_finalize

このstaticコードが明確に使用していたパターン(SQLのプレースホルダーを再利用し、各反復で新しい値をバインドし、後続の各反復の前に実行sqlite3_stmtする)は、まったく同じSQLステートメントを使用しているが、それぞれ新しい値をバインドしている場合に意味があります。反復。しかし、コードのその部分をコメントアウトし、SQLからプレースホルダーを削除し、代わりにを使用してSQLを構築しているようです。?sqlite3_bind_xxxsqlite3_reset?stringWithFormat

最も簡単な解決策は、staticパターンを廃止することで(staticキーワードを削除し、チェックを削除して、の代わりにnil使用する)、問題がないはずです。sqlite3_finalizesqlite3_reset


追加の考え:

  1. 単一の行を更新するたびにデータベースを閉じているようです。多数のレコードを更新する場合は、データベースを開いたままにしておくことを検討することをお勧めします。updateRecordまた、データベースを開いたり閉じたりすることにした場合でも、コード内の同じ論理レベル(両方ともメソッド内、または両方ともメソッド外)でそれらを実行することはおそらく理にかなっていますupdateRecord。より直感的なコードになります。

  2. SQLite関数呼び出しの使用を必要とUPDATEする複数のステートメントを実行するために、以前に準備したSQLステートメントを再利用する必要がないと判断した場合、それらの関数呼び出しの使用を検討する必要がないという意味ではありません。とりあえず。を介してSQLを構築する方がはるかに便利に見えるかもしれませんが、一般的には呼び出しを使用する方が適切です。(b)たとえば、引用符が含まれているパラメーター値のエスケープについて心配する必要はありません。bindbindstringWithFormatsqlite3_bind_xxx

    SQLを構築する習慣を身につけないでくださいstringWithFormat。原則として、SQLは壊れやすく、場合によっては危険です。

  3. SQLでは、通常、数値フィールド値を引用符で囲むことはありません。

  4. static sqlite3_stmt/sqlite3_resetロジックを機能させることにした場合は、次の2つの小さな観察事項があります。

    • データセッション全体で同じものを使用することはありsqlite3_stmtません(つまり、データベースを閉じてから再度開くことはしません)。たぶんそれは機能しますが、データベースがのパラメータであることを考えるとsqlite3_prepare_v2、私はそのような仮定をしません。

    • これを行うときは、最後にデータベースを閉じます。実際にを呼び出しsqlite3_finalizeて、再びsqlite3_stmtに戻す必要がありnilます。

于 2013-01-14T15:50:09.653 に答える
0

データベースを開いていません:-

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

//OPEN DATABASE HERE
[gss initDatabase]; 
static sqlite3_stmt *updateStmt = nil;

    if(updateStmt == nil) {
        NSString *sql = [NSString stringWithFormat:@"update contactList set sapCustId = \"%@\", sapContactId = \"%@\", timestamp = \"%@\" Where record_ID = \"%d\"", sapCustId, sapContactId, timestamp, recordID];

        const char *sql_stmt = [sql UTF8String];

        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_reset(updateStmt);
sqlite3_finalize(updateStmt);
sqlite3_close(databaseHandle);

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

}

コメントで書いたオープンデータベースのコードを追加します。

それがあなたを助けることを願っています。

于 2013-01-14T14:26:58.413 に答える