我们在应用程序中使用sqlite 3.7.14.1代码。最近,我们在从表中删除记录时看到了死锁状态。删除是从两个不同的线程完成并作用于同一个表。
Sqlite在WAL模式下配置。所有线程都打开自己与数据库的共享连接。该应用程序符合SQLITE_THREADSAFE = 1和SQLITE_ENABLE_MEMORY_MANAGEMENT。
m_init = sqlite3_open_v2(
m_dbfilename.toUtf8().data(), /* Database filename (UTF-8) */
&m_dbHandler, /* OUT: SQLite db handle */
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE, /* Flags */
NULL /* Name of VFS module to use */
);
多个线程中的记录的所有更新,插入和删除都发生在事务中。更新/插入语句完全没有任何死锁。但是当两个或多个线程尝试删除同一个表中的条目时,它们将进入死锁状态,其中sqlite3_step继续返回SQLITE_LOCKED。当我们调试代码时
10:00.234 Thread 1 BEGIN
10:00.235 Thread 1 select * from <table1>
10:00.234 Thread 1 select * from <table x>
10:00.456 Thread 1 delete from <table1>
10:00.456 Thread 2 BEGIN
10:00.456 Thread 2 select * from <table1>
10:00.906 Thread 2 select * from <table x>
10:01.156 Thread 2 delete from <table1>
Thread 1 SQLITE_LOCKED(6) Error <Table1> is locked
Thread 2 SQLITE_LOCKED(6) Error database table is locked
线程1是第一个进入BEGIN并对表进行修改的线程,它应该已经获得了表上的WRITE锁定。即使我们认为线程2同时在同一个表上执行select,那么线程2应该在其delete调用中具有锁定表。在这种情况下,没有一个线程在表上锁定并且正在等待。在每个线程中,我们等待一段随机的时间重新执行(sqlite3_step)在准备好的语句上调用reset后的相同预处理语句。
在任何一个场景中,其中一个线程应该成为锁定此表的赢家。
我的问题是如何找到锁定桌子的人。有什么办法可以获得这些信息吗?当并发更新和插入正确发生时,为什么会发生删除?