【发布时间】:2012-08-13 19:43:00
【问题描述】:
我有一个使用 sqlite 数据库的 Web 应用程序。 我的 sqlite 版本是官方 windows 二进制发行版的最新版本 - 3.7.13。
问题是在数据库负载很重的情况下,sqlite API 函数(例如 sqlite3_step)返回 SQLITE_BUSY。
我在初始化连接时传递了以下编译指示:
journal_mode = WAL
page_size = 4096
synchronous = FULL
foreign_keys = on
数据库是单文件数据库。我正在使用 Mono 2.10.8 和它提供的 Mono.Data.Sqlite 程序集来访问数据库。
我正在使用 50 个并行线程对其进行测试,这些线程分别向我的应用程序发送 50 个后续 http 请求。在每次请求时,都会对数据库进行一些读取和写入。每组 IO 操作都在事务内部执行。
在第 400 到 700 个请求之前一切顺利。在这个(随机)时刻,API 函数开始永久返回 SQLITE_BUSY(更准确地说 - 直到达到重试限制)。
据我所知,WAL 模式透明地支持并行读写。我猜这可能是因为在执行检查点操作时尝试读取数据库。但即使关闭自动检查点,情况仍然相同。
在这种情况下会出现什么问题? 如何正确处理大量并行数据库 IO?
附言
假设每个请求只有一个连接。 我使用配置了 WebSessionContext 的 nhibernate。
我像这样初始化我的 NHibernate 会话:
ISession session = null;
//factory variable is session factory
if (CurrentSessionContext.HasBind(factory))
{
session = factory.GetCurrentSession();
if (session == null)
CurrentSessionContext.Unbind(factory);
}
if (session == null)
{
session = factory.OpenSession();
CurrentSessionContext.Bind(session);
}
return session;
在 HttpApplication.EndRequest 我这样发布它:
//factory variable is session factory
if (CurrentSessionContext.HasBind(factory))
{
try
{
CurrentSessionContext.Unbind(factory)
.Dispose();
}
catch (Exception ee)
{
Logr.Error("Error uninitializing session", ee);
}
}
据我所知,每个请求生命周期应该只有一个连接。在处理请求时,代码按顺序执行(ASP.NET MVC 3)。所以看起来这里不可能有任何并发性。我可以断定在这种情况下没有共享连接吗?
【问题讨论】:
-
是为每个请求打开不同的连接,还是所有请求共享同一个连接?另外,您能否添加一些相关的代码,尤其是线程与数据库交互的部分?
-
您对 WAL 模式的假设是错误的。 sqlite.org/wal.html 说:“由于只有一个 WAL 文件,因此一次只能有一个写入器。”对于写入负载较重的数据库,请使用 PostgreSQL 或 MySQL。
标签: multithreading sqlite transactions mono