首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sqlite在WAL模式下返回SQLITE_BUSY

sqlite在WAL模式下返回SQLITE_BUSY
EN

Stack Overflow用户
提问于 2012-08-17 18:55:13
回答 1查看 3K关注 0票数 4

我有一个网络应用程序与sqlite数据库的工作。我的sqlite版本是官方windows二进制发行版3.7.13的最新版本。

问题在于,在数据库负载过重的情况下,sqlite API函数(如sqlite3_step)会返回SQLITE_BUSY。

在初始化连接时,我会传递以下编译指示:

代码语言:javascript
复制
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会话:

代码语言:javascript
复制
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上,我像这样发布它:

代码语言:javascript
复制
//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)。所以看起来这里不可能有任何并发。在这种情况下,我是否可以得出没有共享连接的结论?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-08-29 20:00:30

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

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

因此,假设您没有使用SqliteConnection对象进行锁定,那么您可以尝试一下吗?完成此操作的简单方法可能如下所示:

代码语言:javascript
复制
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中。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12004426

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档