Sqlite数据库被锁定。

12

我正在开发一个 iPhone 应用,当我向数据库插入数据时,我遇到了 "Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while inserting data. 'database is locked''" Error. 错误。

代码如下:

- (NSString *) getDBPath {        
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
        NSString *documentsDir = [paths objectAtIndex:0];
        return [documentsDir stringByAppendingPathComponent:@"Halal.sqlite"];
}

+ (void) finalizeStatements {

            if (database) sqlite3_close(database);
            if (deleteStmt) sqlite3_finalize(deleteStmt);
            if (addStmt) sqlite3_finalize(addStmt);
            if (detailStmt) sqlite3_finalize(detailStmt);
            if (updateStmt) sqlite3_finalize(updateStmt);
}

- (void) gettingData:(NSString *)dbPath {

            NSLog(@"Data base path is %@",dbPath);
            if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
            {
                const char *sql = "select * from Product";
                sqlite3_stmt *selectstmt;
                if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) 
                {
                    while(sqlite3_step(selectstmt) == SQLITE_ROW)
                    {
        [membersInfoDict setValue:[NSString stringWithUTF8String:(char*)sqlite3_column_text(selectstmt, 0)] forKey:@"ProductName"];
                        [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)] forKey:@"ProductBarcode"];
                        [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)] forKey:@"ProductImage"];
                        [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)] forKey:@"ProductIngredients"];
                        [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)] forKey:@"ProductStatus"];


                        if(membersInfoDict)
                        {
                           [membersInfoArray addObject:membersInfoDict];
                           membersInfoDict = nil;
                        //  NSLog(@"Entered and return");
                            return;
                        }
                    }
                }            
            }

            else
                sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.

}


- (void) addRecord:(NSMutableDictionary *)recordDict
{
            if (sqlite3_close(database))
            {
                NSLog(@"Closed");
                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
                NSString *documentsDir = [paths objectAtIndex:0];

                [self gettingData:[documentsDir stringByAppendingPathComponent:@"Halal.sqlite"]];                   
            }   
            else {
                NSLog(@"Not Closed");
            }               
            if(addStmt == nil) {
                const char *sql = "insert into Product(ProductName, ProductBarcode , ProductImage,ProductIngredients,ProductStatus ) Values(?,?,?,?,?)";
                if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
                    NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database));
            }

            sqlite3_bind_text(addStmt, 1, [[recordDict objectForKey:@"ProductName"] UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 2, [[recordDict objectForKey:@"ProductBarcode"] UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 3, [[recordDict objectForKey:@"ProductImage"] UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 4, [[recordDict objectForKey:@"ProductIngredients"] UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(addStmt, 5, [[recordDict objectForKey:@"ProductStatus"] UTF8String], -1, SQLITE_TRANSIENT);


            if(SQLITE_DONE != sqlite3_step(addStmt))
                NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database));
            else
            //SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
                rowID = sqlite3_last_insert_rowid(database);
            NSLog(@"last inserted rowId = %d",rowID);

            //Reset the add statement.
            sqlite3_reset(addStmt);
            //sqlite3_commit_hook();
            //sqlite3_commit_hook(addStmt,[NSString stringWithFormat:@"%d",rowID],database);

}

请提供解决此问题的方案。非常感谢...


你是否在打开“database sqlite3*”时使用了其他查询,导致它仍然保持打开状态? - Ravin
当显示详细信息时,我正在打开数据库。 - Anand
3个回答

18

在你修改的方法中搜索注释 //ADD THIS LINE TO YOUR CODE

- (void) gettingData:(NSString *)dbPath {
    NSLog(@"Data base path is %@",dbPath);
    if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
    {
        const char *sql = "select * from Product";
        sqlite3_stmt *selectstmt;
        if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
        {
            while(sqlite3_step(selectstmt) == SQLITE_ROW)
            {
                [membersInfoDict setValue:[NSString stringWithUTF8String:(char*)sqlite3_column_text(selectstmt, 0)] forKey:@"ProductName"];
                [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)] forKey:@"ProductBarcode"];
                [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)] forKey:@"ProductImage"];
                [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)] forKey:@"ProductIngredients"];
                [membersInfoDict setValue:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)] forKey:@"ProductStatus"];

                if(membersInfoDict)
                {
                    [membersInfoArray addObject:membersInfoDict];
                    membersInfoDict = nil;
                    //  NSLog(@"Entered and return");
                    sqlite3_close(database);
                    return;
                }
            }
        }
        //ADD THIS LINE TO YOUR CODE
        sqlite3_finalize(selectstmt);
    }        
    else
        sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}

1
如果你在返回时没有释放数据库,那么请加上sqlite3_close。 - Vincent
@Vincent,每次访问数据库时您是否应关闭它?此外,我使用一个方法[self openDB]来打开数据库。这种功能分离是否重要,还是应该将所有内容放在同一位置?看起来似乎不重要。 - SonOfSeuss
不需要每次关闭数据库。然而,最好的编程实践是尽可能短地打开和/或锁定数据库。 - Vincent
在 sqlite3_close(database) 之前添加 sqlite3_finalize(selectstmt); 对我很有帮助。 - Brandon

9

在再次打开数据库之前,您需要完成编译的语句并关闭数据库。

sqlite3_finalize(compiledStatement);
sqlite3_close(database);

4
以上答案是正确的,但在模拟器上工作或调试时,数据库出现锁定错误的方法是有的。
情况1:
我在这里解释一个场景,当我向表中插入数据时。并且该数据库正在被任何数据库浏览器访问并从模拟器访问。
现在当您通过模拟器工作于应用程序时,将数据保存到数据库中。现在,如果您使用任何浏览器从该数据库访问数据,并且尝试在浏览器中触发任何更新命令并尝试更新任何一行,它将把该行更新到表中。(现在,当我们从表中删除任何内容时,它总是显示一条消息,即已授予只读权限等)。
现在来到模拟器或者再次运行应用程序,当您尝试向那个表中插入任何数据时,它总是显示错误“数据库已锁定”,因为权限是只读的,而我们却改变了这些权限。现在,如果您尝试更改答案中提到的命令,您将始终得到悲伤的结果。它总是显示数据库已锁定的错误(尽管我尝试过几次来解决这个问题,但每次都失败了)。
唯一摆脱这种情况的方法是:从模拟器中移除应用程序并重新安装它。并避免从浏览器更新/插入任何行。
另一个答案是:
情况2:
当您在sqlite浏览器上工作并进行任何更新时,请确保已保存所有更改,否则会出现锁定条件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接