System.Data.SQLite不支持多个事务

时间:2011-07-19 14:57:30

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

所以我在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()

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

谢谢!

5 个答案:

答案 0 :(得分:14)

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());

答案 1 :(得分:3)

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

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

如果您的应用程序有很多读者而不是很多编写者,那么SQLite可能会很好,但如果您的应用程序包含许多并发读者和编写者,那么您可能会发现完全成熟的数据库服务器是更合适。

有关详细信息,请参阅File Locking And Concurrency In SQLite Version 3

答案 2 :(得分:1)

尝试使用:

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

bool参数讲述了deferredLock。但是,请记住,只有在提交第一个事务后才应调用ExecuteNonScalar。

答案 3 :(得分:-1)

对于它的价值,不支持每个连接的多个事务似乎对数据提供者来说很常见(我肯定知道ODP.NET,可能是其他人)。

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

- 编辑---

卫生署!我刚刚意识到你有多个连接。遗憾。

答案 4 :(得分:-1)

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

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