sqlite在WAL模式下返回SQLITE_BUSY

时间:2012-08-17 10:55:13

标签: multithreading sqlite transactions mono

我有一个使用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?

P.S。

每个请求只能连接一个连接。 我使用配置了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)。因此,这看起来并不像任何可靠性。我可以断定在这种情况下没有共享连接吗?

1 个答案:

答案 0 :(得分:3)

我不清楚请求线程是否共享相同的连接。如果他们不这样做,那么你不应该遇到这些问题。

假设您确实在多个线程之间共享连接对象,您应该使用一些锁定机制作为SqliteConnection isn't thread-safe(一个旧帖子,但作为Mono的一部分维护的SQLite库是从System.Data演变而来的)。 SQLite在http://sqlite.phxsoftware.com)上找到。

因此,假设您没有使用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();如   你喜欢多次,你将永远得到当前的ISession   这个HTTP请求。您必须确保ISession在之后关闭   您的工作单元在Application_EndRequest事件中完成   应用程序类中的处理程序或HTTP之前的HttpModule中的处理程序   回复已发送。