锁定数据库查询FMDB



我在应用程序中使用多线程环境,我需要不断访问sqlite数据库以更新我的视图,还需要通过多个后台线程用服务器数据更新我的数据库。现在我正在使用FMDB进行数据库交互,但仍然存在数据库锁定问题。

FMDatabaseQueue *_queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
NSOperationQueue *_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
NSRecursiveLock *_writeQueueLock = [NSRecursiveLock new];
[_writeQueue addOperationWithBlock:^{
            BOOL tryLock = NO;
            @try {
                [_writeQueueLock lock];
                tryLock = YES;
                [_queue inDatabase:^(FMDatabase *db) {
                    @try {
                        [db logsErrors];
                        [db executeUpdate:updateSQL];
                    }
                    @catch (NSException *exception) {
                    }
                    @finally {
                    }
                }];
            }
            @catch (NSException *exception) {
                NSLog(@"Error while inserting data saveLocation inside operation queue. %@", exception.description);
            }
            @finally {
                if (tryLock) {
                    [_writeQueueLock unlock];
                }
            }
}];

这就是我每次插入数据时所做的,类似于当我锁定时从数据库读取数据时,进程应该在一个线程完成之前无法访问数据库。我不知道怎么了,请帮帮我。

每当多个线程试图访问同一个表进行读写或两个线程想在同一数据库的同一表上写入时,sqlite都会产生数据库锁定信号,因此要解决此问题,您需要锁定

NSRecursiveLock *_writeQueueLock = [NSRecursiveLock new];

正如您在代码中添加的那样,但这对您没有多大帮助,因为您每次插入时都试图强行插入一个新锁。这个锁应该是一个单独的对象,用于所有对DB的阻塞调用,如插入、更新、删除等。

尝试创建锁的单例实例,这应该会有所帮助:

static FMDatabaseQueue *_queue;
static NSOperationQueue *_writeQueue;
static NSRecursiveLock *_writeQueueLock;
+(SomeDBClass*)getSharedInstance{
    if (!sharedInstance) {
        sharedInstance = [[super allocWithZone:NULL]init];
        _queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
        _writeQueue = [NSOperationQueue new];
       [_writeQueue setMaxConcurrentOperationCount:1];
        _writeQueueLock = [NSRecursiveLock new];
    }
    return sharedInstance;
}

现在,一旦创建了对象,就可以在这些队列和锁上调用插入、更新、删除方法,如:

[_writeQueue addOperationWithBlock:^{
            BOOL tryLock = NO;
            @try {
                [_writeQueueLock lock];
                tryLock = YES;
                [_queue inDatabase:^(FMDatabase *db) {
                    @try {
                        [db logsErrors];
                        [db executeUpdate:updateSQL];
                    }
                    @catch (NSException *exception) {
                    }
                    @finally {
                    }
                }];
            }
            @catch (NSException *exception) {
                NSLog(@"Error while inserting data saveLocation inside operation queue. %@", exception.description);
            }
            @finally {
                if (tryLock) {
                    [_writeQueueLock unlock];
                }
            }
}];

你也可以参考这个来更好地理解,希望这能有所帮助,我是新来的,所以请原谅我。谢谢。

使用FMDatabaseQueue完全不需要任何其他锁定机制。添加另一个锁定机制只会使问题进一步复杂化。

如果你收到关于数据库被"锁定"的消息,这是因为:

  • 您有多个FMDatabase/FMDatabaseQueue对象;或

  • 您正在从另一个inDatabase呼叫中呼叫inDatabase

您应该有一个FMDatabaseQueue对象,它在所有线程之间共享,并且您需要确保用inDatabase块调用的函数中没有一个调用其他对象,而该对象本身尝试另一个inDatabase调用。

最新更新