如何debugginglocking的sqlite3数据库

我正在写一个使用由fmdatabase包装的sqlite3的iOS应用程序。 我遇到的问题是,在某些时候,我的程序被卡在FMDatabase库的一个循环中,尤其是一个调用sqlite3_step并发现数据库正忙的函数,然后一遍又一遍地重试。

我正在寻找一般的debugging工具和技巧,因为这将是我的整个设置太多。 有些事情可能是重要的,我打开一个数据库句柄到一个已经在另一个线程中有句柄的数据库。 sqlite3_threadsafe()返回2,所以我知道它的启用。 我也通过一个非常简单的select和更新语句来testing这个新的连接。 当我让我的程序运行,并尝试运行数据库更新时,我卡住了。

我的程序自己的更新语句没有错,因为这个查询运行良好,当我不打开两个连接。 然而,我没有看到我可能会出错的地方…

任何帮助或提示,我可能是错误的将不胜感激。

SQLite在写入操作期间locking整个数据库(例如,在任何表上发生写操作,不能同时发生任何表的任何表写操作)。 有些数据库通过表级锁提供并发写入,有时甚至是行级锁。 为了与SQLite的实现形成鲜明对比,表级locking基本上意味着,当您将数据写入给定的表时,其他线程无法同时写入该表中的任何logging(但是,写入其他表可以在某些情况下同时发生)。 同样,行级别的锁进一步占用它,只允许locking所需的行,允许从多个线程同时写入同一个表。 这里的想法是最大限度地减less写入操作需要locking的数据量,这可以有效地增加数据库的并发写入数量,并根据您的实现/数据库使用情况,可以显着提高吞吐量。

现在回到你的问题

SQLite是线程安全的事实并不意味着多个线程可以同时写入它 – 这意味着它有一个处理来自多个线程的访问的方式 – 这是(a)允许超时/重试,和(b)返回一个有用的错误(SQLITE:繁忙),当数据库当前持有一个锁。 也就是说, 线程安全只不过意味着“multithreading可以以不会因同时访问而导致数据损坏的方式访问这些数据”。

基本上,在代码的某个地方,一个线程试图在另一个线程释放它对数据库的锁之前进行更新。 这是SQLite常见的障碍,因为作者/文档会告诉你,SQLite可以像冠军一样处理并发。 实际情况是,SQLite认为“并发支持”意味着要快速实现,以便数据库的锁只能保持很短的时间,因此在超时之前释放数据库锁。 在很多情况下,这工作得很好,永远不会阻碍你。 但是,拥有非常短暂的locking实际上允许来自多个线程的并发写入不同。

把它想成是iOS多任务处理的方式(至less在我写这篇文章的时候是iOS5),真的是让其他应用程序暂停,然后回到它们。 这样做的效果是:(a)由于CPU利用率较低,电池寿命更好;(b)每次启动时都不必从头开始创build应用程序。 这很棒,但是iOS中使用的“多任务”这个词在技术上并不意味着与其他环境(甚至是Mac OS X)中的“多任务”一样。

SQLite是一样的。 他们有“并发”支持吗? 好吧,但他们定义“并发”这个词的方式并不是数据库世界其余部分定义“并发”的方式。

没有人真的错,但是在这样的情况下,这又增加了执行混乱。