Обработка транзакций в System.Data.Sqlite - PullRequest
0 голосов
/ 14 октября 2018

У меня проблема с пониманием обработки транзакций в System.Data.Sqlite, связанной со следующим фрагментом кода.

public static string ConnenctionString = "Data Source=C:\\DB\\Test.db";

public static void Test1()
{
    SQLiteConnection connection = new SQLiteConnection(ConnenctionString);
    connection.Open();
    SQLiteTransaction transaction = connection.BeginTransaction();
    for (int i = 0; i < 1000000; i++)
    {
        string sql = $"insert into table1 (id) values ({i})";

        SQLiteCommand command = new SQLiteCommand(sql, connection);
        command.ExecuteNonQuery();
    }
    transaction.Commit();

}
public static void Test2()
{
    SQLiteConnection connection = new SQLiteConnection(ConnenctionString);
    connection.Open();
    string sql = "select count(*) from table1";
    SQLiteCommand command = new SQLiteCommand(sql, connection);
    SQLiteDataReader reader = command.ExecuteReader();
    reader.Read();
    Console.WriteLine(reader[0]);
}
public static void Test3()
{
    for (int i = 0; i < 300; i++)
    {
        SQLiteConnection connection = new SQLiteConnection(ConnenctionString);
        connection.Open();
        SQLiteTransaction transaction = connection.BeginTransaction();
        string sql = $"insert into table1 (id) values ({i})";
        SQLiteCommand command = new SQLiteCommand(sql, connection);
        command.ExecuteNonQuery();
        transaction.Commit();
    }
}


static void Main(string[] args)
{
    //Everything is ok

    Task.Factory.StartNew(() => Test1());
    Thread.Sleep(1000);
    Task.Factory.StartNew(() => Test2());

    //Exception db is locked
    Task.Factory.StartNew(() => Test3());
    Thread.Sleep(1000);
    Task.Factory.StartNew(() => Test2());
    Console.ReadLine();
}

В одной задаче я выполняю некоторую длительную операцию (в одной транзакции) - метод Test1.Во второй задаче я пытаюсь выполнить другой запрос без транзакции - метод Test2.Все работает хорошо, я получаю результат, который не включает изменения из Test1 - потому что транзакция еще не была подтверждена.

Но при попытке выполнить в одной задаче большое количество запросов - каждый в отдельной транзакции, как в методе Test3, и в то же время при попытке выполнить метод Test2, я получаю исключение: БД заблокирована.Есть ли способ опустить такое поведение, модифицирующее строку подключения?

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Вы можете попытаться изменить свою базу данных, чтобы она использовала запись с опережением записи .Это позволит одновременный доступ для нескольких задач без блокировки.

ExecuteQuery("pragma journal_mode=WAL");

сразу после создания базы данных.Вы должны выполнить этот оператор только один раз - он постоянен.

0 голосов
/ 14 октября 2018

Я бы порекомендовал использовать с использованием операторов (неудачный каламбур):

using (var connection = new SqliteConnection("conn-string"))
{
    connection.Open();
    using (var transaction = connection.BeginTransaction())
    {
        for (int i = 0; i < 1000000; i++)
        {
            string sql = $"insert into table1 (id) values ({i})";

            using (var command = new SqliteCommand(sql, connection))
            {
                command.ExecuteNonQuery();
            }
        }

        transaction.Commit();
    }
}
...