Mono SQLite无法打开数据库

时间:2012-11-23 14:31:02

标签: c# sqlite mono locking

我编写了一个简单的Mono C#应用程序,用于使用Mono.Data.Sqlite包中的Mono实现写入SQLite数据库:

using System;
using Mono.Data.Sqlite;

class MainClass
{
    public static void Main (string[] args)
    {
        using (var dbConnection = new SqliteConnection (@"Data Source=/var/log/gmblog;Version=3;"))
        {
            dbConnection.Open();

            string sql = @"INSERT INTO ""queue"" (""data"") VALUES(""Test"")";
            using (var insertCommand = new SqliteCommand (sql, dbConnection))
            {
                insertCommand.ExecuteNonQuery();
            }
        }
    }
}

在我从sqlite3等其他应用程序执行插入并保持此应用程序运行之前,此方法正常工作:

sqlite> insert into queue ("data") VALUES("test2");

现在C#程序挂起,直到它出现以下错误:

Unhandled Exception: Mono.Data.Sqlite.SqliteException: The database file is locked

sqlite3的其他实例或我创建的C ++应用程序写入表中没有任何问题。

如果我关闭sqlite3实例,那么C#应用程序将再次运行。

执行lsof /var/log/gmblog表示sqlite3在执行INSERT后获得了读卡器锁定:

sqlite3 15578  cup    3ur  REG   8,17    13312 4988505 /var/log/gmblog

在INSERT之前它没有这个锁:

sqlite3 15578  cup    3u   REG   8,17    13312 4988505 /var/log/gmblog

但正如我所指出的,当其他应用程序使用数据库时,其他应用程序没有任何问题写入表中。

关于我的C#代码有什么问题的任何想法?这是SQLite的Mono实现中的错误吗?

更新25/11

请注意,dbConnection.Open();导致数据库锁定错误,而不是insertCommand.ExecuteNonQuery();。即以下代码也不起作用:

using System;
using Mono.Data.Sqlite;

class MainClass
{
    public static void Main (string[] args)
    {
        using (var dbConnection = new SqliteConnection (@"Data Source=/var/log/gmblog;Version=3;"))
        {
            dbConnection.Open();
        }
    }
}

2 个答案:

答案 0 :(得分:4)

请参阅SQLiteConnection documentation:“如果SQLiteConnection超出范围,则不会关闭。因此,您必须通过调用Close来显式关闭连接。”该示例显示在finally块中关闭连接。我无法在您的代码示例中看到关闭连接的任何位置。

您还应该能够使用“使用”块,当对象超出范围时,该块会自动调用close:

using (var dbConnection = new SqliteConnection (@"..."))
{
    dbConnection.Open();

    string sql = @"INSERT INTO ""queue"" (""data"") VALUES(""Test"")";
    using (var insertCommand = new SqliteCommand (sql, dbConnection))
    {
        insertCommand.ExecuteNonQuery();
    }
}

这可确保所有内容得到及时正确发布。

答案 1 :(得分:1)

我在sqlite的网站上发现了类似discussion的多线程。我知道你不是那里的多线程,而是试图获得写锁定 - 但讨论仍然有一些有用的提示可能有用。

  

然后每个线程继续插入一些记录,假设为1000.您将遇到的问题如下:一个线程将通过设置对文件的锁定来控制数据库。这很好,但是当锁定处于活动状态时,其余的线程将继续针对每次尝试的INSERT失败。

Solution
     

测试SQLITE_BUSY,我最初没做过。这是一些   用于说明解决方案的伪代码:

  while (continueTrying) {
    retval = sqlite_exec(db, sqlQuery, callback, 0, &msg);
    switch (retval) {
      case SQLITE_BUSY:
        Log("[%s] SQLITE_BUSY: sleeping fow a while...", threadName);
        sleep a bit... (use something like sleep(), for example)
        break;
      case SQLITE_OK:
        continueTrying = NO; // We're done
        break;
      default:
        Log("[%s] Can't execute \"%s\": %s\n", threadName, sqlQuery, msg);
        continueTrying = NO;
        break;
    }
  }

您可能还想在连接字符串上尝试busy_timeout参数,如herehere所示。

  

busy_timeout参数实现为对。的调用   源码(3)_busy_timeout。默认值为0,表示抛出一个   如果数据库被锁定,则立即发生SqliteBusyException。