SQLite3有多大程度的线程安全性?

15

关于SQLite3中的多线程,我有一个问题。在我的情况下,我有几个进程想要写入同一个SQLite3数据库。

手册中,它说:

多线程。在此模式下,只要没有单个数据库连接被同时用于两个或更多线程,SQLite就可以安全地由多个线程使用。

我编写了一个示例程序,其中几个(假设为10)线程使用同一个数据库连接向同一数据库的同一个表中插入数据。

CREATE TABLE IF NOT EXISTS StatusTable (ID INTEGER PRIMARY KEY, Thread TEXT NOT NULL, Module TEXT NOT NULL, Status INTEGER NOT NULL);

INSERT是什么?

sprintf(acBuffer, "INSERT INTO StatusTable(Thread, Module, Status) VALUES('%s', 'testnumber%d', %d);", acThread, i, thisThread);

其中 acThread 是包含进程 ID 和线程 ID 的字符串,i 从1到100运行,thisThread 是线程 ID。线程在 while 循环中执行此操作 100 次,然后退出。

根据以上说明,尽管我看不到任何问题,但这是不安全的。

  1. 使用共享的 sqlite3 对象的 10 个线程,每个插入 100 行:没有插入丢失,也没有超时。
  2. 使用 10 个线程,每个单独的 sqlite3 对象插入 100 行:一些插入不成功(约为 0.5 至 1%),因为数据库被锁定。
  3. 使用第一种情况下的两个进程:与第二种情况相同,存在一些损失(约为 0.1%)。

我正在使用 PRAGMA journal_mode=WAL;PRAGMA busy_timeout=10000;

现在我的问题是:

  • 我不应该在线程之间共享连接对象吗?如果这样做会发生什么坏事?
  • 为什么第一种情况(共享 db 连接)可行(所有插入都成功,没有超时)?我该怎么做才能 "打破" SQLite?会发生什么情况?
  • 我假设每个线程都应该有自己的连接。如何避免插入失败?在我的示例中,只有插入操作,没有读取器。荒谬的高 busy_timeout(10 秒)不像预期的那样起作用,仍然存在 "database is locked" 插入故障。只要插入成功,我不介意每个插入等待 10 秒。
2个回答

18

当前SQLite文档(版本3.23.1)指出,默认线程模式为“serialized”,在此模式下:

SQLite可以被多个线程安全地使用,没有任何限制。

线程安全是由编译时控制的。您可以使用以下命令查询SQLite发行版的线程模式:

pragma COMPILE_OPTIONS

感谢@Dennie分享这个cmd pragma COMPILE_OPTIONS。它帮助我找到了SQLite的当前配置。 - OO7

18

这份文档(由创建此软件并长期生活、呼吸和思考它的人编写)告诉你不要共享数据库连接。为什么不直接相信他们呢?毕竟,创建多个数据库连接实际上并不难。

  1. 没错,最糟糕的情况就是未定义行为,可能会包括召唤黑洞、裸奇点和克苏鲁。

  2. 你很幸运。也许你测试中的所有一百次插入都在下一个线程甚至开始之前就已经完成了。

  3. 你的假设是正确的。你可以通过测试并在遇到问题时重复SQL命令来避免失败。设置高超时时间是没有帮助的。

Sqlite并不是处理任何需要多线程(或多进程)访问数据库的问题的一个特别好的选择,而且在这种场景下,“数据库锁定”消息几乎是无法避免的。从单个线程访问数据库,并将插入组合成一个语句(即使用多值插入)可以获得更好的性能。如果这还不够,用多个线程攻击sqlite数据库将完全不会提高性能。如果你有这样一种使用情况,你应该考虑安装一个专门为此目的构建的数据库,比如PostgreSQL。


非常感谢。我会尽量避免黑洞 :-) 你能给我一个关于多值插入的链接吗?我理解它不仅仅是“INSERT ...; INSERT ...; INSERT ...;”。 - Fabian
1
您可以在单个插入语句中插入多个值:http://sqlstudies.com/2013/02/28/insert-multiple-values-sets-into-a-table-in-one-command/。这比相同数量的单个插入要快得多。 - H. Guijt
"你很幸运。" - 或不幸,这取决于一个人对软件健壮性和多线程错误调试的看法 :) 无论如何,非常好的答案,+1。 - Christian Hackl
1
没错。你与数据库签订了一份合同——如果你遵守它,你可以责怪它违反了自己的部分——否则,你就会迷失…… - tofro

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