当前位置:  开发笔记 > 编程语言 > 正文

SQLite并发访问

如何解决《SQLite并发访问》经验,为你挑选了7个好方法。

SQLite3是否安全地处理来自同一个DB读取/写入的多个进程的并发访问?有没有平台例外?



1> kijin..:

如果大多数并发访问是读取(例如SELECT),SQLite可以很好地处理它们.但如果你开始同时写,锁争用可能会成为一个问题.然后很大程度上取决于文件系统的速度,因为SQLite引擎本身非常快,并且有许多聪明的优化来最小化争用.特别是SQLite 3.

对于大多数台式机/笔记本电脑/平板电脑/手机应用程序,SQLite足够快,因为没有足够的并发性.(Firefox广泛使用SQLite作为书签,历史等)

对于服务器应用程序,前段时间有人说在一般情况下(例如博客,论坛),SQLite数据库可以完美地处理每天少于100K的页面浏览量,而我还没有看到任何相反的证据.实际上,使用现代磁盘和处理器,95%的网站和Web服务可以与SQLite一起使用.

如果您想要快速读/写访问,请使用内存中的SQLite数据库.RAM比磁盘快几个数量级.


OP不询问效率和速度,而是关于并发访问.Web服务器与它无关.在内存数据库中也是如此.

2> vcsjones..:

是的,SQLite很好地处理并发性,但从性能角度来看并不是最好的.据我所知,没有例外.详细信息在SQLite的网站上:https://www.sqlite.org/lockingv3.html

这个陈述很有意思:"寻呼机模块确保一次性发生变化,发生所有变更或者没有变更,两个或多个进程不会同时以不兼容的方式访问数据库"


[以下是关于不同平台上的问题的一些评论](http://www.sqlite.org/faq.html#q5),即NFS文件系统和Windows(尽管它可能仅适用于旧版本的Windows ... )

3> akc42..:

似乎没有人提到WAL(Write Ahead Log)模式.确保事务处理正确并且启用了WAL模式,在进行更新时人们正在阅读内容时无需锁定数据库.

唯一的问题是,在某些时候需要将WAL重新合并到主数据库中,并且在最后一次连接到数据库时关闭它.对于非常繁忙的站点,您可能会发现所有连接都需要几秒钟才能关闭,但每天100K的点击量应该不是问题.



4> ffeast..:

是的,它确实.让我们找出原因

SQLite是事务性的

SQLite中单个事务中的所有更改要么完全发生,要么根本不发生

这种ACID支持以及并发读/写以两种方式提供 - 使用所谓的日记(让我们称之为" 旧方式 ")或预写日志(让我们称之为" 新方式 ")

日记(旧路)

在这种模式下,SQLite使用DATABASE-LEVEL 锁定.这是理解的关键点.

这意味着无论何时需要读取/写入内容,它都会首先获取ENTIRE数据库文件的锁定.多个读者可以并行共存和阅读

在写入期间,它确保获得独占锁定,并且没有其他进程同时读取/写入,因此写入是安全的.

这就是为什么在这里他们说SQlite的实现序列化交易

故障

因为它需要每次都锁定整个数据库,并且每个人都在等待进程处理写入并发性受损并且此类并发写入/读取性能相当低

回滚/中断

在向数据库文件写入内容之前,SQLite首先将要更改的块保存在临时文件中.如果在写入数据库文件的过程中发生崩溃,它将获取此临时文件并从中恢复更改

预写日志或WAL(新方式)

在这种情况下,所有写入都附加到临时文件(预写日志),并且此文件定期与原始数据库合并.当SQLite搜索某些东西时,它会首先检查这个临时文件,如果没有找到,则继续使用主数据库文件.

因此,与Old Way相比,读者不会与作家竞争,而且表现要好得多.

注意事项

SQlite在很大程度上取决于底层文件系统锁定功能,因此应谨慎使用,此处有更多详细信息

您也可能会遇到数据库锁定错误,尤其是在日记模式下,因此您的应用程序需要在设计时考虑到此错误



5> obgnaw..:

SQLite支持无限数量的同时读者,但它只允许一个编写者在任何时刻.在许多情况下,这不是问题.作家排队.每个应用程序都可以快速完成数据库工作并继续运行,并且锁定持续时间超过几十毫秒.但是有些应用程序需要更多的并发性,而这些应用程序可能需要寻求不同的解决方案.

在DOC中很清楚.

在事务处理中,SQLite通过数据库级​​别的独占锁和共享锁实现独立的事务处理.这就是为什么多个进程可以同时从同一个数据库读取数据的原因,但只有一个进程可以写入数据库.

在进程或线程想要对数据库执行写操作之前,必须获得独占锁.获得独占锁之后,不会再发生其他读或写操作.

实现细节,例如两个写:

SQLite有一个锁表,可以帮助在最后一刻锁定不同的写数据库,以确保最大的并发性.

初始状态为"UNLOCKED",在此状态下,连接尚未访问数据库.当数据库连接到数据库并且甚至已使用BEGIN启动事务时,连接仍处于"未锁定"状态.

解锁状态的下一个状态是SHARED状态.为了能够从数据库读取(不写入)数据,连接必须首先进入SHARED状态,也就是说,首先获得SHARED锁定.多个连接可以同时获取和维护SHARED锁,也就是说,多个连接可以同时从同一个数据库读取数据.但即使只发布了一个SHARED锁,也不允许任何连接写入数据库.

如果连接想要写一个数据库,它必须首先得到一个RESERVED锁.

虽然多个SHARED锁可以与单个RESERVED锁共存,但一次只能激活一个RESERVED锁.RESERVED与PENDING的不同之处在于,当存在RESERVED锁时,可以获取新的SHARED锁.

一旦连接获得RESERVED锁,它就可以开始处理数据库修改操作,尽管这些修改只能在缓冲区中完成,而不是实际写入磁盘.对读出内容的修改保存在内存缓冲区中.当连接想要提交修改(或事务)时,必须将保留锁升级为独占锁.要获得锁定,您必须先将锁解除挂锁.

PENDING锁意味着持有锁的进程想要尽快写入数据库,并且只是等待所有当前的SHARED锁清除,以便它可以获得EXCLUSIVE锁.如果PENDING锁处于活动状态,则不允许对数据库使用新的SHARED锁,但允许继续使用现有的SHARED锁.

为了写入数据库文件,需要一个EXCLUSIVE锁.文件上只允许一个EXCLUSIVE锁,并且不允许任何其他类型的锁与EXCLUSIVE锁共存.为了最大化并发性,SQLite可以最大限度地减少EXCLUSIVE锁定所需的时间.

因此,SQLite安全地处理来自同一个数据库的多个进程的并发访问,因为它不支持它.当它达到重试限制时,你将获得SQLITE_BUSYSQLITE_LOCKED为第二个编写器获取.


您是否可以使用一个队列并让多个线程提供该队列,而只有一个线程使用该队列中的SQL语句写入数据库。像[this]之类的东西(https://gist.github.com/User001501/3053f26100ddf281600668fed347e518)

6> V.B...:

在2019年,有两个新的并发写入选项尚未发布,但可在不同的分支中使用.

"PRAGMA journal_mode = wal2"

这种日志模式优于常规"wal"模式的优点是作者可以继续写入一个wal文件,而另一个是检查点.

BEGIN CONCURRENT - 链接到详细的文档

该BEGIN并发增强允许多个作家,以写处理交易simultanously如果数据库是在"沃"或"wal2"模式,但系统仍然连载COMMIT命令.

当使用"BEGIN CONCURRENT"打开写事务时,实际锁定数据库将被推迟,直到执行COMMIT.这意味着以BEGIN CONCURRENT开始的任何数量的事务可以同时进行.系统使用乐观页面级锁定来防止提交冲突的并发事务.

它们一起存在于begin-concurrent-wal2中或者每个都存在于一个单独的分支中.


不知道。您可以从分支轻松构建。对于.NET,我有一个具有低级接口和WAL2的库+开始并发+ FTS5:https://github.com/Spreads/Spreads.SQLite

7> 小智..:

这个线程很旧但我认为分享我在sqlite上完成的测试结果会很好:我运行2个python程序实例(不同进程同一个程序)执行语句SELECT和UPDATE sql命令在事务中使用EXCLUSIVE锁定和超时设置为获得锁定10秒钟,结果令人沮丧.每个实例都在10000步循环中完成:

使用独占锁连接到db

选择一行读取计数器

使用等于计数器的新值更新行加1

与db的紧密连接

即使sqlite在事务上授予了独占锁定,实际执行的周期总数也不等于20 000但更少(两个进程计算的单个计数器的迭代总数).Python程序几乎没有抛出任何单个异常(在选择20次执行期间只有一次).测试时的sqlite修订版是3.6.20和python v3.3 CentOS 6.5.在我看来,最好为这种工作找到更可靠的产品,或者将sqlite的写入限制为单一的唯一进程/线程.


看起来你需要说一些神奇的词来获得python中的锁定,如下所述:http://stackoverflow.com/a/12848059/1048959尽管python sqlite文档引导你相信`with con`就足够了.
推荐阅读
yzh148448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有