更新SQLite数据库时,应用程序与Assertion Failure消息崩溃

时间:2013-01-17 09:43:10

标签: ios sqlite sql-update xcode4.5

在我的应用程序中,我在本地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];

}

请帮助!..

2 个答案:

答案 0 :(得分:1)

所以,有几点想法:

  1. 正如Prateek和Lefteris建议的那样,您应该更改bind调用的顺序,以便它们与SQL中字段的顺序相匹配。它们也以一个索引开始,而不是零。我总是觉得奇怪的是sqlite3_bind调用的索引从1开始,而sqlite3_column调用的索引从零开始,但它只是它的工作方式。

  2. 虽然它可能没什么问题,但如果你做过断言,你通常应该先确保(a)完成任何成功准备的陈述; (b)关闭数据库。您不希望冒险将数据库置于不一致状态。

  3. 您可能不应在此处发布sapContactIdsapCustId。你没有retain或做任何事情来增加他们的保留计数,所以在这里释放他们可能并不谨慎。如果您通过静态分析器运行代码(按 shift + 命令 + B 或从产品菜单中选择“分析”),你'毫无疑问会在那里看到建议/警告。

  4. 正如官方SQLite An Introduction To the SQLite C/C++ Interface中所述,您的openprepare_v2stepfinalize和{{1}的序列是完全正确的。您无需致电closesqlite3_reset的{​​{3}}允许您重复使用之前准备的reset,但您在此处没有这样做,因此此处不需要sqlite3_stmt,也不会实现任何目标。< / p>

  5. 在评论的某一点,您说您收到错误“数据库已锁定”。如果你仍然已经解决了上述问题,请告诉我们你在哪里获得它(在reset?在SQL语句的open期间?),因为可能有不同的来源这个问题。当然,多线程数据库操作可能会导致这种情况。您需要帮助我们通过向您详细说明您获取此锁定消息的哪一行来诊断这一点,并描述您可能正在做的其他数据库操作(原始问题中的代码之外),特别是如果您正在执行任何操作后台队列/线程。

    解决“数据库锁定”问题的挑战在于,问题总是存在于您遇到“数据库锁定”错误的代码中,而是在您之前无法正确处理的某些数据库交互中。从技术上讲,未能调用prepare可能会导致“数据库锁定”问题,但实际上很少出现这种情况。我看到通常由于其他问题而发生“数据库锁定”错误,但我们确实需要知道您是在数据库打开期间,还是在尝试sqlite3_finalizeprepare SQL时遇到错误声明。您需要告诉我们哪些可供我们进一步诊断。但是,就像我说的那样,问题无疑取决于其他/先前的数据库交互,因此您可能需要分享更多关于您在之前执行“数据库锁定”错误的其他数据库操作。< / p>


  6. 如果您对原始问题中有关重写代码的讨论感兴趣,请参阅下文。

    一个小建议,但我建议更改step方法,以确保在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语句。

    • 如果您使用断言或从执行数据库交互的方法中间返回,您总是希望进行优雅的清理。例如,您将看到我的准备工作是否失败,我只是关闭,但如果if失败,那么我确保stepfinalize

    • 您可能应该删除那些不恰当的close语句,将它们移到代码中的正确位置。

    • 您应该将方法签名更改为具有命名参数(因为在编码指南的purpose部分中, Apple说我们应该命名我们的方法关键字。

    因此:

    release

答案 1 :(得分: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();,因此您收到数据库锁错误。