SQLite3是否安全处理多个进程的并发访问 读/写从相同的DB?有什么平台例外吗?
当前回答
如果大多数并发访问是读(例如SELECT), SQLite可以很好地处理它们。但是如果开始并发地编写,锁争用就会成为一个问题。这在很大程度上取决于您的文件系统有多快,因为SQLite引擎本身非常快,并且有许多巧妙的优化来最小化争用。尤其是SQLite 3。
对于大多数台式机/笔记本电脑/平板电脑/手机应用程序,SQLite已经足够快了,因为没有足够的并发性。(Firefox在书签、历史记录等方面广泛使用SQLite)
对于服务器应用程序,前段时间有人说过,在典型的场景下(例如博客、论坛),SQLite数据库可以完美地处理每天少于10万的页面浏览量,我还没有看到任何相反的证据。事实上,使用现代磁盘和处理器,95%的网站和web服务都可以很好地使用SQLite。
如果你想要快速的读/写访问,请使用内存中的SQLite数据库。内存比磁盘快几个数量级。
其他回答
这个线程是旧的,但我认为它会很好地分享我在sqlite上做的测试的结果: 我运行了2个python程序实例(不同进程相同程序),在事务中执行语句SELECT和UPDATE sql命令,并将EXCLUSIVE锁和超时设置为10秒以获得锁,结果令人沮丧。在10000步循环中执行的每个实例:
使用排他锁连接数据库 在一行上选择以读取计数器 用等于计数器加1的新值更新行 关闭数据库连接
Even if sqlite granted exclusive lock on transaction, the total number of really executed cycles were not equal to 20 000 but less (total number of iterations over single counter counted for both processes). Python program almost did not throw any single exception (only once during select for 20 executions). sqlite revision at moment of test was 3.6.20 and python v3.3 CentOS 6.5. In mine opinion it is better to find more reliable product for this kind of job or restrict writes to sqlite to single unique process/thread.
似乎没有人提到WAL(预写日志)模式。确保事务被正确组织,并设置了WAL模式,当人们在更新时读取数据时,没有必要保持数据库锁定。
唯一的问题是,在某些情况下,WAL需要重新合并到主数据库中,并且在到数据库的最后一个连接关闭时这样做。对于一个非常繁忙的网站,你可能会发现需要几秒钟才能关闭所有连接,但每天10万次点击应该不是问题。
当您为db指定名称时,如果您有并发访问(特别是写),甚至在内存db中指定名称时,很自然会得到这个结果。 在我的例子中,我使用Sqlite进行测试,这是因为在同一个解决方案中有几个测试。 你可以有两个改进:
在创建db.Database.EnsureDeletedAsync(); 使用空字符串进行连接,在这种情况下,每次调用都会创建一个随机名称:
{
"ConnectionStrings": {
"ConnectionType": "sqlite",
"ConnectionString": ""
}
}
如果大多数并发访问是读(例如SELECT), SQLite可以很好地处理它们。但是如果开始并发地编写,锁争用就会成为一个问题。这在很大程度上取决于您的文件系统有多快,因为SQLite引擎本身非常快,并且有许多巧妙的优化来最小化争用。尤其是SQLite 3。
对于大多数台式机/笔记本电脑/平板电脑/手机应用程序,SQLite已经足够快了,因为没有足够的并发性。(Firefox在书签、历史记录等方面广泛使用SQLite)
对于服务器应用程序,前段时间有人说过,在典型的场景下(例如博客、论坛),SQLite数据库可以完美地处理每天少于10万的页面浏览量,我还没有看到任何相反的证据。事实上,使用现代磁盘和处理器,95%的网站和web服务都可以很好地使用SQLite。
如果你想要快速的读/写访问,请使用内存中的SQLite数据库。内存比磁盘快几个数量级。
是的。 让我们来看看为什么
SQLite是事务性的
SQLite中单个事务中的所有更改都可能发生 完全或根本没有
这种ACID支持以及并发读/写是通过两种方式提供的——使用所谓的日志记录(我们称之为“旧方式”)或预写日志记录(我们称之为“新方式”)
日志(旧方式)
在这种模式下,SQLite使用数据库级锁定。 这是需要理解的关键。
这意味着当它需要读/写一些东西时,它首先在整个数据库文件上获得一个锁。 多个阅读器可以共存并并行阅读
在写入过程中,它确保获得一个排他锁,并且没有其他进程同时读写,因此写入是安全的。
这就是为什么这里说SQlite实现了可序列化的事务
麻烦
由于它每次都需要锁定整个数据库,每个人都在等待一个处理写入的进程,并发性受到影响,这种并发写/读的性能相当低
回滚/中断
在向数据库文件写入内容之前,SQLite首先会将要更改的块保存在一个临时文件中。如果在写入数据库文件的过程中发生了崩溃,它将拾取这个临时文件并恢复其中的更改
预写测井或WAL(新方法)
在这种情况下,所有写操作都被追加到一个临时文件(预写日志),并且该文件定期与原始数据库合并。 当SQLite搜索某些东西时,它会首先检查这个临时文件,如果没有发现,则继续检查主数据库文件。
因此,读者不会与作者竞争,与旧的方式相比,表现要好得多。
警告
SQlite在很大程度上依赖于底层的文件系统锁定功能,因此应该谨慎使用,更多细节请点击这里
你也可能会遇到数据库锁定错误,特别是在日志模式下,所以你的应用程序需要在设计时考虑到这个错误
推荐文章
- 创建存储过程和SQLite?
- SQLite并发访问
- 如何连接字符串与填充在sqlite
- 在Android SQLite中处理日期的最佳方法
- SQLite数据库文件使用什么扩展名重要吗?
- 无法加载DLL 'SQLite.Interop.dll'
- 快速简单的方法迁移SQLite3到MySQL?
- 在Ubuntu上安装sqlite3-ruby错误
- sqlite3。ProgrammingError:提供的绑定数量不正确。当前语句使用1,并提供了74个
- SQLite有。net / c#包装器吗?
- Android开发有什么好的ORM工具吗?
- 如何在SQLite中看到表的结构?
- Android中使用的SQLite版本?
- Core Data vs SQLite 3
- 如何在SQLITE中删除或添加列?