0

我的应用程序使用 SQLite 数据库来存储联系人的某些数据。例如(record_ID、时间戳等)我正在尝试使用此方法使用某些值更新 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

关键问题是您的代码只构建updateStmt一次,因为那是 astatic并且您正在检查它是否不是nil. 因此,第一个 SQL 语句正在构建,但其余的都没有。最简单的解决方法是去掉static预选赛和if(updateStmt == nil) ...逻辑,你应该去参加比赛。另外,请确保将 替换sqlite3_resetsqlite3_finalize

如果您使用完全相同的 SQL 语句,但每个都只是绑定新值static,那么这段代码显然习惯使用的模式(通过每次迭代重用 SQL 中的sqlite3_stmt,​​ 绑定?占位符和新值,在每次后续迭代之前执行)是有意义的迭代。但看起来您已经注释掉了那部分代码并从 SQL 中删除了占位符,而是使用.sqlite3_bind_xxxsqlite3_reset?stringWithFormat

最简单的解决方案是退出static模式(摆脱static关键字,消除检查以查看它是否为nil,并使用sqlite3_finalize代替sqlite3_reset),你应该没问题。


额外的想法:

  1. 每次更新单行时,您似乎都在关闭数据库。如果您要更新一堆记录,您可能需要考虑保持数据库打开。即使您决定打开和关闭数据库,在代码中的相同逻辑级别执行这些操作也可能有意义(无论是在updateRecord方法内部,还是在方法外部updateRecord)。它只是使代码更直观。

  2. 假设您决定不想费心重复使用以前准备好的 SQL 语句来执行多个UPDATE语句,这需要使用 SQLitebind函数调用,但这并不意味着您不应该考虑使用这些bind函数调用反正。虽然通过 构建 SQL 看起来更方便stringWithFormat,但通常最好使用sqlite3_bind_xxx调用,因为 (a) 可以保护您免受注入攻击;(b) 您不必担心转义参数值,例如,其中包含引号等。

    不要养成用 SQL 构建 SQL 的习惯,stringWithFormat因为一般来说,它很脆弱,而且在某些情况下很危险。

  3. 在您的 SQL 中,您通常不会在数字字段值周围使用引号。

  4. 如果您决定尝试使static sqlite3_stmt/sqlite3_reset逻辑工作,有两个小观察:

    • 我不会sqlite3_stmt在数据会话中使用相同的方法(即不要关闭数据库然后重新打开它)。也许它有效,但鉴于数据库是 的参数sqlite3_prepare_v2,我不会做出任何这样的假设。

    • 当您最终关闭数据库时,您真的应该调用sqlite3_finalizesqlite3_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 回答