为什么不允许在SQLite数据库上进行并发写入?


79

我正在使用Java和SQLite进行数据库编程。

我发现一次只与数据库的一个连接具有写功能,而一次有许多连接具有读功能。

为什么SQLite的架构是这样设计的?只要要写入的两件事没有被写入数据库中的同一位置,为什么不能同时发生两次写入?



5
因为SQLite被设计为“精简版”。低内存和低处理性能。请仔细考虑如何使SQLite处理对同一文件的多次写入。当前的设计易于实现-整个文件被锁定,其他文件必须等待。要以较低的粒度处理写并发,需要从RDMS获得行/页锁定。如果需求要求写并发性,那么SQLite是不是候选人,而是,你应该看看轻量级RDBMS:en.wikipedia.org/wiki/...
托马斯卡莱尔

Answers:


157

因为在核心数据库引擎中完成“多个并发写入”要比单写入器,多读取器难得多。它超出了SQLite的设计参数,包括在内可能会破坏SQLite令人愉悦的小尺寸和简单性。

支持高度的写并发性是大型数据库引擎(例如DB2,Oracle,SQL Server,MySQL,PostgreSQL,NonStop SQL和Sybase)的标志。但这在技术上很难实现,需要广泛的并发控制和优化策略,例如数据库,表和行锁定,或者在更现代的实现中需要多版本并发控制。关于这个问题/要求的研究是大量的,可以追溯到几十年前

SQLite与大多数支持多个编写器的以服务器为中心的DBMS的设计理念截然不同。它旨在将SQL和关系模型的功能带给各个应用程序,并且确实可以嵌入到每个应用程序中。这个目标需要重大的权衡。其中之一就是不增加处理多个并发编写器所需的重要基础架构和开销。

可以通过在SQLite的适当使用页面上的一条语句来总结这种哲学:

SQLite不与客户端/服务器数据库竞争。SQLite与fopen()竞争。


41
+1。SQLite是一个进程内数据库。没有像基于服务器的数据库中那样的中央仲裁器。作家将必须直接合作并互相信任。单个恶意编写者可能会因为不合作而造成严重破坏。
约尔格W¯¯米塔格

12
此外,SQLite执行的某些环境甚至可能不支持多个进程。
david25272 '17

1
大概是恶意写操作可能由于不合作而造成了严重破坏。他们不能使用SQLite代码来执行此操作,但是可以拥有自己的代码,这可能只是对unlink()的调用
bdsl

12
在并发应用程序中,没有很多中间立场。基本上在100%的时间内都能获得并发性,一致性和数据完整性,包括在具有挑战性的条件和极端情况下,或者您没有。如果您不这样做,它会变得脆弱,缓慢且容易崩溃,并且人们会很快停止信任它。但是,将其例行正确地做起来很难。在没有核心支持的情况下,没有很多情况下作家可以自行协调交错的写作。
乔纳森·尤尼斯

8
任何形式的@bdsl数据库必须承担的作家不会是乖巧的,这样他们就不会丢失数据。作者SQLite将其定位为的竞争对手fopen(),因此请考虑并发写入纯文本文件所带来的所有麻烦。
Blrfl

12

因为没有服务器可以告诉您是否要将内容写入同一位置。尝试写入文件只有两个过程。

如评论中所指出的,内部线程也可以支持并发写入。不确定这样做的效果如何(也没有考虑太多)。无论如何,这就是为什么SQLite不使用线程的原因:Hipp博士认为线程是邪恶的。

SQLite FAQ中记录了DR Hipp认为线程是邪恶的事实。


2
这解释了为什么不允许并发写入的技术原因,而不是为什么做出设计决定的原因。
罗伯特·哈维

3
设计SQLite使其一次仅处理一次写入的决定。
罗伯特·哈维

7
@Goyo不需要服务器来处理并发写入:就像数据库服务器是一个单独的进程一样,SQLite内部可能有一个单独的线程可以达到相同的目的。Robert Harvey是正确的:SQLite团队做出了一项设计决策,这与单个库处理并发写入的能力无关(因为从理论上讲可以这样做)。

1
这个答案对我来说似乎很好。要处理并发写入,似乎需要服务器或多线程sqlite实现。因为这两个都已被其他设计决策所排除,所以实现并发写入将非常困难。
jpa

5
@jpa:SQLite设法在没有“服务器”的情况下在多个进程/线程之间同步锁定。不需要“服务器”-使用操作系统提供的锁定/同步/ IPC /只要足够,就可以很快地变得复杂。帖子中提到的“内螺纹”没有意义。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.