【问题标题】:System.Data.SQLite Not Supporting Multiple TransactionsSystem.Data.SQLite 不支持多个事务
【发布时间】:2011-10-08 14:54:45
【问题描述】:

所以我在 System.Data.SQLite 和使用多个事务时遇到了一个有趣的问题。基本上我有以下代码失败:

using (IDbConnection connection1 = new SQLiteConnection("connectionstring"), connection2 = new SQLiteConnection("connectionstring"))
{
    connection1.Open();
    connection2.Open();

    IDbTransaction transaction1 = connection1.BeginTransaction();
    IDbTransaction transaction2 = connection2.BeginTransaction();    // Fails!

    using(IDbCommand command = new SQLiteCommand())
    {
        command.Text = "CREATE TABLE artist(artistid int, artistname text);";
        command.CommandType = CommandType.Text;
        command.Connection = connection1;
        command.ExecuteNonQuery();
    }

    using (IDbCommand command = new SQLiteCommand())
    {
        command.Text = "CREATE TABLE track(trackid int, trackname text);";
        command.CommandType = CommandType.Text;
        command.Connection = connection2;                    
        command.ExecuteNonQuery();
    }

    transaction1.Commit();
    transaction2.Commit();

}

根据我的阅读,System.Data.SQLite 似乎应该支持嵌套和扩展顺序事务。代码在第 7 行(声明第二个事务)失败,但出现以下异常:

System.Data.SQLite.SQLiteException: The database file is locked

System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
System.Data.SQLite.SQLiteDataReader.NextResult()
System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()

有谁知道问题是什么或如何解决这个问题?我觉得并发事务对于任何数据库系统都是必不可少的,所以必须有某种方法来做到这一点。

谢谢!

【问题讨论】:

  • 非常仔细地查看您的代码...在第一个 using 语句中您是新的 command1 但您引用了 command

标签: c# sql sqlite system.data.sqlite


【解决方案1】:

尝试使用:

((SQLiteConnection)connection).BeginTransaction(true)-

bool 参数说明 deferredLock。但是,请记住 ExecuteNonScalar 只能在提交第一个事务后调用。

【讨论】:

    【解决方案2】:

    OP 在 2 个连接上启动事务,这是问题开始的地方,而不是多个事务本身。

    SQLiteConnection conn = new SQLiteConnection("data source=:memory:");
    conn.Open();
    
    var command = conn.CreateCommand();
    command.CommandText = "create table a (b integer primary key autoincrement, c text)";
    command.ExecuteNonQuery();
    
    var tran1 = conn.BeginTransaction();
    var tran2 = conn.BeginTransaction();
    
    var command1 = conn.CreateCommand();
    var command2 = conn.CreateCommand();
    
    command1.Transaction = tran1;
    command2.Transaction = tran2;
    
    command1.CommandText = "insert into a VALUES (NULL, 'bla1')";
    command2.CommandText = "insert into a VALUES (NULL, 'bla2')";
    
    command1.ExecuteNonQuery();
    command2.ExecuteNonQuery();
    
    tran1.Commit();
    tran2.Commit();
    
    command.CommandText = "select count(*) from a";
    Console.WriteLine(command.ExecuteScalar());
    

    【讨论】:

      【解决方案3】:

      SQLite 被设计为一个轻量级数据库,用于存储浏览器中的书签或照片目录程序中的照片。 SQLite 有一个非常精细的锁定系统,该系统针对具有多个读取器或单个读取器/写入器线程的场景进行了优化。因此,众所周知,并发写入存在性能问题 - 它根本不适合在具有许多并发写入者的应用程序中使用。您可以进行并发写入,但它不会很好地扩展。

      在这种情况下,问题是因为您正在尝试进行并发架构更改 - 如果您改为执行多个 SELECT 或多个 INSERT 语句,那么此成功运行(如 Sixfeetsix 的回答所示)。

      如果您的应用程序有很多读取器而写入器不多,那么 SQLite 可能很好,但是如果您的应用程序有很多并发读取器和写入器,那么您可能会发现一个成熟的数据库服务器是更合适。

      更多详情请参阅File Locking And Concurrency In SQLite Version 3

      【讨论】:

      • 这样的第三个答案...... sqlite 确实支持多个事务。
      • 是的,当我现在更好地理解你的观点时,我会稍微收回所说的话,但我的观点是,如果我把自己放在 OP 的立场上,我会发现我希望社区更直接地解决我的问题,即坚持告诉我多个写入连接是问题,然后作为额外的讨论为什么只坚持一个事务可能会更好。
      • +1 因为这正是我想要做的——多个连接,每个都有一个事务保存到数据库——但这在 SQLite 中根本不支持。
      【解决方案4】:

      SQLite 不支持多事务 - 它在事务中锁定整个数据库(参见 www.sqlite.org)。

      编辑: 支持多个事务,但在多个事务中使用 DDL 时不支持。

      【讨论】:

      • 当您比较 Oracle 和 SQLite 中的多个事务支持时,您会看到 SQLite 只是“模拟”对它的支持......您的示例和原始问题之间存在差异,您使用 DML,他在两个交易中都使用 DDL...我相应地调整了我的答案。
      【解决方案5】:

      不管怎样,对于数据提供者来说,每个连接不支持多个事务似乎很常见(我肯定知道 ODP.NET,可能还有其他)。

      解决此问题的一种方法是为每个单独的IDbTransaction 设置一个单独的IDbConnection

      -- 编辑 ---

      哇!我刚刚意识到您确实有多个连接。对不起。

      【讨论】:

      • sqlite 支持多事务。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多