【问题标题】:sqlite database updates only 1 recordsqlite 数据库仅更新 1 条记录
【发布时间】:2013-01-14 14:12:04
【问题描述】:

我的应用程序使用 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];

}

告诉我。如何解决?

【问题讨论】:

  • 你在哪里打开你的数据库?
  • 在我调用 updateRecord 方法的地方打开它.. 即首先我调用 [gss initDatabase];然后 [gss updateRecord:record_ID:sapCustId:sapContactId:timestamp];
  • 你为什么不打电话给sqlite3_finalize
  • 摆脱那些静态的东西,并确保准备、执行和完成每个UPDATE SQL 语句。如果 (a) 您正在绑定语句而不是每次都从头开始构建 SQL,则您可以使用保留的 sqlite3_stmt 做一些事情; (b) 您并非一直在打开和关闭数据库。
  • @ibiren 非常好。我在那里提供了answer。但是,一般来说,当您告诉我们您遇到了一个断言错误,但您并没有告诉我们断言是什么时,这令人沮丧。您完成所有这些工作以执行sqlite3_errmsg 以获得很好的描述性错误消息,然后您不会与我们分享它们。始终告诉我们 (a) 断言是什么、完整的内容以及任何相关的 NSLog 声明; (b) 告诉我们它在哪里。

标签: ios sqlite ios6 sql-update xcode4.5


【解决方案1】:

关键问题是您的代码只构建了一次updateStmt,因为这是一个static,而您正在检查它是否不是nil。因此,第一个 SQL 语句正在构建,但其余的都没有。最简单的解决方法是去掉static 限定符以及if(updateStmt == nil) ... 逻辑,你应该去参加比赛了。另外,请确保将sqlite3_reset 替换为sqlite3_finalize

此代码明显用于执行的static 模式(重用sqlite3_stmt,通过sqlite3_bind_xxx 每次迭代将SQL 中的? 占位符与新值绑定,在每次后续迭代之前执行sqlite3_reset)使得感觉您是否使用完全相同的 SQL 语句,但每次迭代只是绑定新值。但看起来您已经注释掉了那部分代码并从 SQL 中删除了 ? 占位符,而是使用 stringWithFormat 构建 SQL。

最简单的解决方案是取消static 模式(去掉static 关键字,取消检查它是否为nil,并使用sqlite3_finalize 代替sqlite3_reset)然后你应该没问题。


其他想法:

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

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

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

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

  4. 如果您决定尝试使 static sqlite3_stmt/sqlite3_reset 逻辑工作,请注意两个小问题:

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

    • 当您最终关闭数据库时,您确实应该在 sqlite3_stmt 上调用 sqlite3_finalize 并再次将其设置回 nil

【讨论】:

    【解决方案2】:

    你没有打开你的数据库:-

    - (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];
    
    }
    

    在我在评论中写的地方添加你的开放数据库的代码。

    希望对你有帮助..

    【讨论】:

    • 在正确的位置调用initDatabase方法后,也没有更新数据库中的记录。 (在我的 -didselectrow 方法中,我使用手动输入调用 UPDATERECORD 方法。)#not getting any error
    • @ibiren 复制我编辑的代码并粘贴它,你错过了一些行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    相关资源
    最近更新 更多