在更新SQLite数据库时,应用程序与断言失败消息一起崩溃

在我的应用程序中,我保存在本地Sqlite数据库中的一些数据。 Sqlite打开,插入所有工作正常。 但是当我尝试更新数据的特定行/logging如果失败与安慰失败消息..

*声明失败 – [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]; } 

请帮忙!

尝试这个

你缺lesssqlite3_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(); 在你以前的任何function,所以你正在获取数据库locking错误..

所以,有一些想法:

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

  2. 虽然这可能是好的,但如果你做了断言,你通常应该确保你首先(a)完成任何成功准备的陈述; 和(b)closures数据库。 您不希望让数据库处于不一致的状态。

  3. 您可能不应该在这里释放sapContactIdsapCustId 。 你没有retain或做任何事情来增加他们的保留数量,所以在这里发布它们可能不是一个明智的做法。 如果您通过静态分析器运行代码(按Shift + Command + B或从产品菜单中select“分析”),那么您无疑会在那里看到build议/警告。

  4. 正如在官方SQLite中概述的那样, SQLite C / C ++接口简介中 , openprepare_v2stepfinalizeclose顺序是完全正确的。 你不需要调用sqlite3_resetreset的目的是让你重用以前准备好的sqlite3_stmt ,但是你没有这样做,所以在这里reset是不必要的,什么也不做。

  5. 在你的评论中的某一点,你说你收到一个错误“数据库locking”。 如果您仍然在解决上述问题,请告诉我们您在哪里(在prepare SQL语句期间open ?),因为这个问题可能有不同的来源。 当然multithreading数据库操作可能会导致这种情况。 您需要帮助我们通过向我们显示确切地知道哪条线路获取此locking消息来诊断此问题,并描述您可能正在执行的其他数据库操作(超出原始问题中的代码),特别是如果您在一个后台队列/线程。

    解决“数据库locking”问题的难题在于,问题总是不在您遇到“数据库locking”错误的代码中,而在以前的数据库交互中,您无法正确处理。 从技术上讲,没有调用sqlite3_finalize可能会导致“数据库locking”的问题,但实际情况很less如此。 我发现由于其他问题通常会发生“数据库locking”错误,但是我们确实需要知道在数据库打开期间,还是在尝试prepare或执行SQL语句时是否遇到了这种错误。 您需要告诉我们哪些要我们进一步诊断。 但是,正如我所说的,这个问题无疑在其他/以前的数据库交互中,因此您可能需要在“数据库locking”错误之前分享更多关于您正在执行的其他数据库操作的信息。


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

一个小build议,但我会build议改变你的initDatabase方法,以确保你logging错误消息,如果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语句。

  • 如果您使用断言或从执行数据库交互的方法中返回,则始终需要进行优雅的清理。 例如,你会看到如果我的准备失败,我会closures,但如果step失败,那么我确定finalizeclose

  • 您可能应该摆脱那些不适当的release声明,将它们移到代码中的正确位置。

  • 您应该更改方法签名以具有命名参数(因为在“ 编码指南”的“ 通用规则”部分中 Apple表示我们应该命名方法关键字。

从而:

 - (void) insertRecord:(int)recordID sapCustId:(NSString *)sapCustId sapContactId:(NSString *)sapContactId timestamp:(NSString *)timestamp { [self initDatabase]; sqlite3_stmt *statement = nil; const char *sql_stmt = "INSERT INTO contactList (sapCustId, sapContactId, timestamp, record_ID) VALUES (?, ?, ?, ?)"; if(sqlite3_prepare_v2(databaseHandle, sql_stmt, -1, &statement, NULL) != SQLITE_OK) { NSLog(@"%s: insert prepare error: '%s'", __FUNCTION__, sqlite3_errmsg(databaseHandle)); sqlite3_close(databaseHandle); NSAssert(0, @"insert prepare error"); } sqlite3_bind_text(statement, 1, [sapCustId UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 2, [sapContactId UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 3, [timestamp UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_int(statement, 4, recordID); if (sqlite3_step(statement) != SQLITE_DONE) { NSLog(@"%s: insert step error: '%s'", __FUNCTION__, sqlite3_errmsg(databaseHandle)); sqlite3_finalize(statement); sqlite3_close(databaseHandle); NSAssert(0, @"insert step error"); } sqlite3_finalize(statement); sqlite3_close(databaseHandle); }