我有一个网络应用程序与sqlite数据库的工作。我的sqlite版本是官方windows二进制发行版3.7.13的最新版本。
问题在于,在数据库负载过重的情况下,sqlite API函数(如sqlite3_step)会返回SQLITE_BUSY。
在初始化连接时,我会传递以下编译指示:
journal_mode = WAL
page_size = 4096
synchronous = FULL
foreign_keys = on数据库为单文件数据库。我正在使用Mono2.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 MVC3)。所以看起来这里不可能有任何并发。在这种情况下,我是否可以得出没有共享连接的结论?
发布于 2012-08-29 20:00:30
我不清楚请求线程是否共享相同的连接。如果他们没有,那么你就不应该有这些问题。
假设你确实是在多个线程之间共享连接对象,你应该使用一些锁定机制作为SqliteConnection isn't thread-safe (一个旧的帖子,但是SQLite库是从http://sqlite.phxsoftware.com上的System.Data.SQLite演变而来的Mono的一部分)。
因此,假设您没有使用SqliteConnection对象进行锁定,那么您可以尝试一下吗?完成此操作的简单方法可能如下所示:
static readonly object _locker = new object();
public void ProcessRequest()
{
lock (_locker) {
using (IDbCommand dbcmd = conn.CreateCommand()) {
string sql = "INSERT INTO foo VALUES ('bar')";
dbcmd.CommandText = sql;
dbcmd.ExecuteNonQuery();
}
}
}但是,您可以选择打开与每个线程的不同连接,以确保您不会再遇到SQLite库的线程问题。
编辑
在您发布的代码之后,您会在提交事务后关闭会话吗?如果你不使用一些ITransaction,你会刷新并关闭会话吗?我之所以问这个问题,是因为我在您的代码中看不到它,而我在https://stackoverflow.com/a/43567/610650中看到了它
我在http://nhibernate.info/doc/nh/en/index.html#session-configuration上也看到了
还请注意,您可以调用NHibernateHelper.GetCurrentSession();只要您愿意,您将始终获得此HTTP请求的当前ISession。您必须确保在您的工作单元完成之后关闭ISession,无论是在应用程序类的Application_EndRequest事件处理程序中还是在发送HTTP响应之前的HttpModule中。
https://stackoverflow.com/questions/12004426
复制相似问题