【发布时间】:2011-10-30 13:48:38
【问题描述】:
我有一段 C++ 代码,它创建了许多线程,每个线程都访问一个通用 SQLite 数据库以及 SELECTs 和 INSERTs 数据。
所有 INSERT 都包含在事务中。很多时候我收到“数据库已锁定”错误。
我该如何解决这个问题?
【问题讨论】:
标签: c++ multithreading sqlite
我有一段 C++ 代码,它创建了许多线程,每个线程都访问一个通用 SQLite 数据库以及 SELECTs 和 INSERTs 数据。
所有 INSERT 都包含在事务中。很多时候我收到“数据库已锁定”错误。
我该如何解决这个问题?
【问题讨论】:
标签: c++ multithreading sqlite
我主要是想指出,正如一些人所假设的那样,您不应该让多个用户写入同一个 SQLite DB,因为这不是它的设计目的;
(5) 可以多个应用程序或同一个实例的多个实例 应用程序同时访问一个数据库文件?
多个进程可以同时打开同一个数据库。 多个进程可以同时执行 SELECT。但只有 一个进程可以随时更改数据库 然而,时间。
SQLite 使用读/写锁来控制对数据库的访问。 (在不支持读/写锁的 Win95/98/ME 下,一个 而是使用概率模拟。)但要小心:这个 如果数据库文件是,锁定机制可能无法正常工作 保存在 NFS 文件系统上。这是因为 fcntl() 文件锁定是 在许多 NFS 实现上都被破坏了。你应该避免把 SQLite 如果多个进程可能会尝试访问 NFS 上的数据库文件 同时归档。在 Windows 上,微软的文档说 如果您没有运行 Share.exe 守护进程。对 Windows 有丰富经验的人 告诉我网络文件的文件锁定是非常错误的,不是 可信。如果他们说的是真的,共享一个 SQLite 数据库 两台或多台 Windows 机器之间可能会导致意外问题。
我们知道没有其他嵌入式 SQL 数据库引擎支持 与 SQLite 一样多的并发性。 SQLite 允许多个进程拥有 数据库文件一次打开,供多个进程读取 数据库一次。当任何进程要写入时,它必须锁定 更新期间的整个数据库文件。但这通常 只需要几毫秒。其他进程只是等待作者 完成然后继续他们的业务。其他嵌入式 SQL 数据库引擎通常只允许单个进程连接到 数据库。
但是,客户端/服务器数据库引擎(例如 PostgreSQL、MySQL 或 Oracle)通常支持更高级别的并发性并允许 多个进程同时写入同一个数据库 时间。这在客户端/服务器数据库中是可能的,因为有 始终有一个受控良好的服务器进程可用于协调 使用权。如果您的应用程序需要大量并发,那么 您应该考虑使用客户端/服务器数据库。但是经验 表明大多数应用程序需要的并发性远低于它们的 设计师想象。
当 SQLite 试图访问被另一个进程锁定的文件时, 默认行为是返回 SQLITE_BUSY。你可以调整这个 C 代码的行为 使用 sqlite3_busy_handler() 或 sqlite3_busy_timeout() API 函数。
【讨论】:
您可以以多线程方式使用 SQLite,但您必须为每个线程打开一个新连接 (sqlite3_open()) 并对该连接进行操作。
【讨论】:
如果您在多个线程上仅使用“BEGIN”开始事务,然后使用 INSERT,则 sqlite 可能会死锁。
那是因为 sqlite 只在 BEGIN 上获得一个读锁。在 INSERT 上,它必须将该读锁升级为写锁(只有在没有读锁的情况下才能这样做)。 journal_mode=WAL(只有默认的 journal_mode=delete)不会发生这种情况,因为 wal 模式允许在写入期间进行读取访问。 (因此使用 WAL 模式可能是一种解决方法)。
解决方案: 如果您计划在事务中使用插入,请使用 BEGIN IMMEDIATE。这样 sqlite 会在数据库上获得写锁。
【讨论】: