尽管受互斥锁保护,SQLite 更新失败并显示 'database is locked'

SQLite updates failing with 'database is locked' despite being mutex-protected

问题:我有多个进程访问同一个 SQLite 数据库,所有进程都试图更新同一行、同一 table 中的相同 3 列。 UPDATEsqlite3_mutex 保护(UPDATEsqlite3_mutex_entersqlite3_mutex_leave 括起来)。这是行不通的,其中一个更新失败并显示 'database is locked'.

是很常见的

更详细地说,每个进程都是由 Apache 创建的,它响应来自客户端的多个(大约十几个)异步 Ajax 请求。每个请求都从记录当前时间开始,用于会话管理,因此我在“相同”时间执行 UPDATE 时得到 12 个进程全部 运行 (日志都显示它们 运行 在同一秒,具有唯一的 PID,但我没有检查更精确的时间)。

数据库由 sqlite3_open 使用默认选项打开,因此被序列化。

那么,显而易见的问题 - 为什么这行不通?我不认为互斥量的使用是错误的,那么 'busy' 期间是否可以超出互斥量保持时间?我可以做的一件事是用 sqlite3_open_v2 打开数据库,然后改为多线程而不是序列化(因为每个进程都有一个唯一的数据库连接)——这会有帮助吗?

我添加了以下代码的简化版本。正在执行的语句是 UPDATE users SET Limit1=%lx, Limit2=%lx, Limit3=%lx WHERE UserName='%s',其中 % 字段在运行时以类似 C 的方式填充。

谢谢。

   // sqlite3 version 3.26.0, Linux
   sqlite3_mutex *mutex = sqlite3_db_mutex(con);
   assert(mutex);
   sqlite3_mutex_enter(mutex);
   rc = sqlite3_exec(con, statement, 0, 0, 0);
   if(rc != SQLITE_OK)
      ... save error message from sqlite3_errmsg
   else
      ... save the changed row count from sqlite3_changes
   sqlite3_mutex_leave(mutex);

294

在 windows 中你可以尝试这个程序 http://www.nirsoft.net/utils/opened_files_view.html 来找出正在处理 db 文件的进程。尝试关闭解锁数据库的程序

在 Linux 和 macOS 中你可以做类似的事情,例如,如果你的锁定文件是 development.db:

$ fuser development.db

此命令将显示锁定文件的进程:

> development.db: 5430

杀死进程...

kill -9 5430

...您的数据库将被解锁。

您提到使用多个进程,并且正在使用专为“线程同步”设计的SQLite mutexes

重要的是,在 Windows 上,它们是通过临界区实现的,而在 Unix 平台上,它们是通过未设置 PTHREAD_PROCESS_SHARED 标志的 pthread 互斥体实现的。在这两种情况下,它们只在一个进程的范围内工作,每个进程都有自己的一组互斥体供 SQLite 使用。

如果你想阻止多个进程访问同一个数据库,你需要使用你自己命名的互斥锁或其他进程间锁定机制。