SQLite3 - iOS - 数据库被锁定

4

我正在开发一款iPad应用程序,并使用sqlite句子(select,update,insert,delete)。

我在开头打开数据库(sqlite3_open),并在每个语句结束时关闭(sqlite3_close)。但有时我会收到“数据库已锁定”的消息。

我不知道如何解决这个问题。

谢谢,很抱歉这些信息不多。


你需要提供更多信息,比如数据库的位置在哪里,你在什么查询上收到了“锁定”消息,你如何查询数据库,是否关闭了结果集。现在没有足够的信息。我现在唯一能想到的是,数据库文件是只读的,因为它在应用程序包(资源)中。 - rckoenes
可能是重复的 链接 - Scar
4个回答

7
如果我没有理解错误,关于 SQLLite 的问题在于一次只能访问一个。如果有多个线程,会发生这种情况。举个例子:
- 在 t1 线程上运行访问数据库的 method1。 - 在 x 秒后,在 t2 线程上运行访问数据库的 method2。
如果在 x 秒内 method1 没有完成,那么两个方法将同时访问它。正如我所说,我知道 SQLLite 不支持这样做。
你应该尝试标记数据库的使用情况,如果你想要访问它但正在使用中,请在 x 秒后再试一次。就像这样:
- (void) generalMethodThatUsesDatabses
{
    if(databaseIsUsed)
    {
         [self performSelector:@selector(generalMethodThatUsesDatabses) withObject:nil afterDelay:5];
          return;
    }

    databaseIsUsed = TRUE;   //global bool variable


    //your code here

    databaseIsUsed = FALSE;

}

希望这可以帮到你。干杯!

谢谢,我会检查所有的代码并使用你的标志;)有结果时我会进行评论。 - javiazo
我认为这种情况是由于你说它只会“有时”发生。因此,这可能取决于信息的数量,以及某个操作所需的时间。 - George
谢谢,非常感谢!!;) 多亏了这些标志,我已经能够找到错误了。一个是我在另一个语句内部打开了数据库,另一个错误是我在没有关闭数据库的情况下在语句中使用了 "return"。 - javiazo
很高兴能帮忙。确实,使用协议会更好。像我写的那样在 x 秒后进行调度,在最坏的情况下会让你损失 x-1 秒。即使这大约是 3-4 秒,它仍然是一个你不想要的冻结。 - George
如果可以接受阻塞等待,您也可以在访问数据库时使用 @synchronized 域。 - Krumelur
使用额外的变量并不能保证线程安全。您需要使用来自 fw 的 synchronized。 - Sazzad Hissain Khan

3
你可能在使用相同的模拟器之前打开了数据库。 为了将所有操作记录到数据库并释放所有资源,你必须始终使用这两个语句:
sqlite3_finalize(statement);
sqlite3_close(database);

很多初学者只包括sqlite3_close语句,假设在关闭期间finalize会自动执行。但事实并非如此。 - Vincent

0
一个解决这个问题的好方法是将其封装成一个C++库。这样,您可以在堆栈上创建库包装器。这意味着当函数超出范围时,您可以在析构函数中关闭连接。
(请注意,我在Objective-C中使用引用计数)
例如:
NSArray* ScoreBoard::getAllScores()
{ 
      ScoreBoard::ensureExistingTable();

      //Stack allocated
      SqliteWrapper sqlite("Scores.sqlite");

     NSArray* result = sqlite.RunQuery("SELECT * FROM Scores ORDER BY ID DESC");

     return result;
     //after this, the sqlite destructor is called
}

Objective-C编译器允许您合并C++,这非常好。它可以非常有用。

另外

 void SqliteWrapper::Close()
 {
     sqlite3_close(db);
 }

正如Vincent所指出的那样,您必须完成语句。如果您想保持连接开放,请在每个语句后使用finalize。在您丢弃连接时立即关闭连接。

这种方法对我很有效。


-1

它用于三种方法: 1.插入 2.更新 3.删除。

-(NSMutableArray *)resultSet
-(void)insertWithTitle:(NSString *)title Body:(NSString *)body
-(BOOL)updateAtIndex:(int)index Title:(NSString *)title Body:(NSString *)body

NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];

FMResultSet *rs = [db executeQuery:[self SQL:@"SELECT * FROM %@" inTable:TABLE_NAME]];
while ([rs next]) {
    Record *tr = [[Record alloc] initWithIndex:[rs intForColumn:@"id"]
                                         Title:[rs stringForColumn:@"title"]
                                          Body:[rs stringForColumn:@"body"]];
    [result addObject:tr];
    [tr release];
}

[rs close];

2....

return result;
[db executeUpdate:[self SQL:@"INSERT INTO %@ (title, body) VALUES (?,?)" inTable:TABLE_NAME], title, body];
if ([db hadError]) {
    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);

删除记录:

BOOL success = YES;
[db executeUpdate:[self SQL:@"DELETE FROM %@ WHERE id = ?" inTable:TABLE_NAME], [NSNumber numberWithInt:index]];
if ([db hadError]) {
    NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
    success = NO;
}
return success;

}

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