我的应用程序使用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];
}
让我知道。,如何解决?
答案 0 :(得分:1)
关键问题是,您的代码只构建updateStmt
一次,因为它是static
并且您正在检查它是否不是{{1} }}。因此,第一个SQL语句正在构建,但其余的都没有。最简单的解决方法是摆脱nil
限定符以及static
逻辑,你应该参加比赛。另外,请务必将if(updateStmt == nil) ...
替换为sqlite3_reset
。
此代码明确用于执行的sqlite3_finalize
模式(在SQL中重用static
,绑定sqlite3_stmt
占位符,每次迭代通过?
执行新值,执行{ {1}}在每次后续迭代之前)如果你正在使用完全相同的SQL语句但只是在每次迭代时绑定新值,那么这是有意义的。但看起来您已经注释掉了部分代码并从SQL中删除了sqlite3_bind_xxx
占位符,而是使用sqlite3_reset
构建SQL。
最简单的解决方案是退出?
模式(删除stringWithFormat
关键字,取消检查以查看它是否为static
,然后使用{{ 1}}代替static
),你应该没事。
其他想法:
每次更新单行时,您似乎都在关闭数据库。如果您要更新一堆记录,您可能需要考虑保持数据库处于打开状态。即使您决定打开和关闭数据库,在代码中处于相同逻辑级别(在nil
方法内部或在sqlite3_finalize
方法之外)都可能有意义。 。它只是为了提供更直观的代码。
假设您决定不想重复使用以前准备好的SQL语句来执行多个sqlite3_reset
语句,这些语句将要求使用SQLite updateRecord
函数调用,这并不意味着你不应该考虑使用那些updateRecord
函数调用。虽然通过UPDATE
构建SQL可能看起来更方便,但通常最好使用bind
调用,因为(a)可以保护您免受注入攻击; (b)您不必担心转义参数值,例如,在其中加上引号等等。
不要养成使用bind
构建SQL的习惯,因为作为一般规则,它很脆弱,在某些情况下,它很危险。
在SQL中,通常不会在数字字段值周围使用引号。
如果您决定尝试stringWithFormat
/ sqlite3_bind_xxx
逻辑工作,那么会有两个小的意见:
我不会在数据会话中使用相同的stringWithFormat
(即不要关闭数据库然后重新打开它)。也许它有效,但鉴于数据库是static sqlite3_stmt
的参数,我不会做出任何这样的假设。
当你最后关闭数据库时,你真的应该在sqlite3_reset
上拨打sqlite3_stmt
并再次将其设置回sqlite3_prepare_v2
。
答案 1 :(得分: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];
}
添加我在评论中写过的开放数据库的代码。
希望它可以帮助你..