如何处理多线程访问sqlite3时避免出现数据库锁定错误

6
在我的应用程序中,后台sqlite线程正在运行...在后台线程中,它从Web服务获取数据并将其插入或更新到数据库中。如果用户在前台插入或删除数据,有时会导致崩溃,并显示“sqlite dblocked”错误,但它不会返回sqlite忙错误。
我测试了线程安全模式。
     NSLog(@" sqlite3_threadsafe() = %d", sqlite3_threadsafe());

IT显示线程安全是2。

我想检查是否有其他数据库正在写入数据,如果数据库正在写入数据...我想在上一次写入任务完成后再写入数据。

如何处理这些情况...

3个回答

9
您可以使用锁(例如在线程编程指南同步部分中列举的那些锁),或者您可以使用专用串行队列。例如,创建一个队列:
@property (nonatomic, strong) dispatch_queue_t databaseQueue;

实例化它:

self.databaseQueue = dispatch_queue_create("com.company.app.database", 0);

每当您想与数据库进行交互时,可以执行以下操作

dispatch_sync(self.databaseQueue, ^{
    // do your database activity here
});

如果您想简化生活,FMDB 库有一个 FMDatabaseQueue 对象,可以为您完成大部分工作(同时还极大地简化了您的数据库交互)。

如果我在这里使用全局队列,会有什么区别吗? - Mrugesh Tank
@MrugeshTank - 这是一个并发队列,所以在这里不会有帮助。事实上,多线程访问是那些需要对数据库进行某种形式的同步的事情之一。 - Rob

2
线程安全模式可以防止多个线程访问同一连接而导致崩溃,但不能防止多个连接相互干扰。为了保护所有数据库事务,请使用通用锁;可以使用互斥锁或@synchronized指令

我想要检查是否有其他的写入进程正在运行。如果有其他任务在运行,等待直到它完成...这可能吗? - banu
1
这就是这些锁所做的事情。 - CL.
请问您如何处理数据库锁定问题? - banu
1
你在哪方面遇到了文档的问题? - CL.
1
这是你的代码问题,而不是文档的问题,看起来你没有阅读和理解文档。 - CL.

1

SQLite文档中得知:

使用SQLITE_THREADSAFE编译参数选择线程模式。如果没有SQLITE_THREADSAFE编译参数,则使用序列化模式。可以通过-DSQLITE_THREADSAFE=1来明确表示。使用-DSQLITE_THREADSAFE=0将使用单线程模式。使用-DSQLITE_THREADSAFE=2将使用多线程模式。

因此,看起来您的SQLite处于多线程模式,但未序列化。在此模式下,您不能从不同的线程使用相同的数据库连接,但如果在每个线程中打开不同的连接,则是安全的。


是的,我正在使用不同的线程。我的问题是有时会出现数据库被锁定的错误。 - banu
你需要在每个线程中打开不同的数据库连接,或者重新构建SQLite以串行模式运行(使用SQLITE_THREADSAFE=1)。 - asandroq
我有 sqlite3_threadsafe() == 2,并在不同线程同时执行事务时放置了这行代码 sqlite3_config(SQLITE_CONFIG_SERIALIZED)。这样做可以吗? - mr5

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