System.Data.SQLite Not Supporting Multiple Transactions

怎甘沉沦 提交于 2019-12-08 14:53:55

问题


So I am having an interesting issue with System.Data.SQLite and using multiple transactions. Basically I have the following code which fails:

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

}

From what I've read it seems that System.Data.SQLite should support nested and by extension sequential transactions. The code fails on line 7 (where the second transaction is declared) with the following exception:

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

Does anyone know what the issue is or how to get around this? I feel having concurrent transactions is essential for any database system so there must be some way to do this.

Thanks!


回答1:


OP is initiating transactions on 2 connections, that's where problems start, not multiple transactions per se.

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



回答2:


SQLite is designed as a lightweight database for things like the bookmarks in a browser, or the photos in a photo catalog program. SQLite has a very granular locking system which is optimised for scenarios with either many readers or a single reader / writer thread. As such it is known to have performance problems with concurrent writes - it is simply not designed for use in applications with many concurent writers. You can do concurrent writes, but it won't scale well.

In this case the problem is because you are attempting to make concurrent schema changes - if you instead did multiple SELECT or multiple INSERT statements then this will work successfully (as sixfeetsix's answer shows).

If your application has many readers and not many writers then SQLite may well be fine, however if you have an application with many concurrent readers and writers then you may find that a fully fledged database server is more suitable.

See File Locking And Concurrency In SQLite Version 3 for more detail.




回答3:


Try to use:

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

The bool parameter tells about the deferredLock. But, remember the ExecuteNonScalar should be called only after the first transaction is commited.




回答4:


For what it's worth, not supporting multiple transactions per single connection seems to be common for data providers (I know for sure ODP.NET, probably others).

One way to work around it is to have a separate IDbConnection for each separate IDbTransaction.

-- EDIT ---

Doh! I just realized you do have multiple connections. Sorry.




回答5:


SQLite does not support multiple transaction - it locks the complete database when in a transaction (see www.sqlite.org).

EDIT: Multiple transactions are supported but not when using DDL in more than one transaction.



来源:https://stackoverflow.com/questions/6749270/system-data-sqlite-not-supporting-multiple-transactions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!