锁定数据库查询 FMDB?

Locks on DB queries 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];
                }
            }
}];

这就是我每次插入数据时所做的,以及当我在锁定时从数据库中读取数据时以类似的方式进行的操作,在一个线程完成之前,进程不应该能够访问数据库。我不知道出了什么问题,请帮帮我。

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

NSRecursiveLock *_writeQueueLock = [NSRecursiveLock new];

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

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

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];
                }
            }
}];

您也可以参考 this 以获得更好的理解,希望这对您有所帮助,我是堆栈的新手所以请多多包涵谢谢。

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

如果您收到关于数据库 "locked" 的消息,那是因为:

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

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

你应该有一个 FMDatabaseQueue 对象,它在所有线程之间共享,你需要确保 none 用 inDatabase 块调用的函数调用其他东西它本身会尝试另一个 inDatabase 调用。