我对SQLite3中的多线程有疑问。在我的场景中,我有几个进程,它们想要写入相同的SQLite3数据库。
在manual中,它说
Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
我编写了一个示例程序,其中有几个(比如10个)线程使用相同的数据库连接INSERT到同一个数据库的同一个表中。
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次,然后退出。
根据上述说法,虽然我看不出任何问题,但这并不安全。
我正在使用PRAGMA journal_mode=WAL;
和PRAGMA busy_timeout=10000;
。
现在我的问题:
答案 0 :(得分:6)
文档(由创建此软件并且多年来生活,呼吸和思考的人员编写)告诉您不要共享数据库连接。你为什么不简单地相信他们?这并不是说创建多个数据库连接实际上非常困难。
是的,这是真的。可能发生的最糟糕的事情是未定义的行为,可能包括或不包括召唤黑洞,裸体奇点和克苏鲁。
你很幸运。在下一个线程开始之前,测试中的所有插入都可能已经执行。
你假设正确。您可以通过测试来避免失败,并在遇到错误时重复SQL命令。设置高超时无济于事。
对于任何对数据库进行多线程(或多进程)访问的问题,Sqlite并不是特别匹配,根据我的经验,“数据库被锁定”消息在这种情况下几乎是不可避免的。通过从单个线程访问数据库,并将插入组合到单个语句中(即使用多值插入),可以获得更好的性能。如果这还不够,那么使用多个线程敲定一个sqlite数据库将不来帮助提高性能。如果你有一个需要这种方法的用例,你应该考虑安装一个为此目的而构建的数据库,比如PostgreSQL。
答案 1 :(得分:3)
当前的SQLite(版本3.23.1)文档指出默认的线程模式是“序列化”,并且在此模式下:
多个线程可以安全地使用SQLite,没有任何限制。
线程安全控制在compile-time。您可以使用以下命令查询SQLite发行版的线程模式:
pragma COMPILE_OPTIONS