Как выполнить SQLite-запрос с помощью считывателя данных без блокировки базы данных?

Я использую System.Data.Sqlite для доступа к базе данных SQLite на C #. У меня есть запрос, который должен читать строки в таблице. Во время итерации по строкам и пока средство чтения открыто, необходимо выполнить определенные обновления SQL. Я использую заблокированную базу данных.

В документации по SQLite говорится:

Когда процесс хочет прочитать из файла базы данных, он выполняет следующую последовательность шагов:

  1. Откройте файл базы данных и получите блокировку SHARED.

В документации также говорится о блокировке SHARED:

База данных может быть прочитана, но не записана. Любое количество процессов может одновременно удерживать SHARED-блокировки, следовательно, может быть много одновременных считывателей. Но никакому другому потоку или процессу не разрешено писать в файл базы данных, пока активны одна или несколько блокировок SHARED.

В FAQ говорится:

Одна и та же база данных может быть открыта одновременно у нескольких процессов. Несколько процессов могут выполнять SELECT одновременно. Но только один процесс может вносить изменения в базу данных в любой момент времени.

Книга Полное руководство по SQLite гласит:

... соединение может выбрать уровень изоляции чтение-незафиксированный с помощью прагмы read_uncommited. Если для него установлено значение true, соединение не будет блокировать чтение таблиц, которые оно читает. Следовательно, другой писатель может фактически изменить таблицу, поскольку соединение в режиме чтения-незафиксирования не может ни блокироваться, ни блокироваться другими соединениями.

Я попытался настроить прагму на чтение незафиксированных в операторе команды запроса SQL следующим образом:

PRAGMA read_uncommitted = 1;
SELECT Column1, Column2 FROM MyTable

Обновление SQL в том же потоке с использованием другого соединения по-прежнему не удалось с исключением заблокированной базы данных. Затем я попытался установить уровень изоляции на чтение незафиксированных в экземпляре соединения. По-прежнему без изменений, за тем же исключением.

Как я могу добиться того, чтобы считыватель открытых данных перебирал строки в базе данных без блокировки базы данных, чтобы я мог выполнять обновления?

Обновление:

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


person Elan    schedule 20.03.2011    source источник


Ответы (2)


Используйте режим WAL.

person Doug Currie    schedule 20.03.2011
comment
Я использую ADO.Net. Согласно sqlite.phxsoftware.com, версия System.Data.SQLite.dll - 1.0.66.0 18 апреля. , 2010, а версия SQLite - 3.6.23.1. Похоже, мне нужна версия 3.7+ для использования WAL. Какие-либо предложения? Есть ли обновленный провайдер ADO.Net? - person Elan; 21.03.2011
comment
Да, см. system.data.sqlite.org/index .html / doc / trunk / www / index.wiki версия 1.0.68.0 от февраля 2011 года представляет собой слияние кода с SQLite 3.7.5. - person Doug Currie; 21.03.2011
comment
Выглядит многообещающе; к сожалению, я еще не увидел ничего готового или доступного для загрузки ... Выпуск 1.0.68.0, о котором вы говорите, официально доступен, или это альфа / бета? - person Elan; 21.03.2011
comment
Исходный код доступен для скачивания; система сборки все еще находится в стадии разработки из-за сложности различных инструментов и целей сборки, насколько я понимаю. - person Doug Currie; 21.03.2011
comment
У меня есть последняя версия исходного кода: github.com/PaulS/SQLiteDotNetProvider. Он предназначен для vs2008, использует старую систему сборки, которая все еще работает. Похоже, что для завершения сборки их нового проекта нет этажа. Я внес изменения кода из официального проекта, их очень мало. - person P a u l; 22.03.2011
comment
Возможно, сделать копию файла db и читать из него, изменяя оригинал? В конце концов, это sql LITE :) - person Sharas; 27.06.2014
comment
С помощью System.Data.SQLite.Core вы можете сделать это, добавив journal mode = Wal в строку подключения. - person Foole; 22.07.2014
comment
@DougCurrie любые советы для меня здесь < / а>? - person zelusp; 27.10.2016

Мне не удалось заставить это работать с помощью поставщика данных с открытым исходным кодом, который можно найти здесь. Однако мне удалось заставить это работать, используя бесплатную стандартную версию dotConnect. следующее:

Создайте нижеприведенный импорт DLL, чтобы мы могли включить общий кеш для SQLite.

[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int sqlite3_enable_shared_cache(int enable);

Выполните указанную выше функцию, чтобы включить общий кеш. Обратите внимание: это нужно выполнить только один раз для всего процесса - см. документацию по SQLite.

sqlite3_enable_shared_cache(1);

Затем префикс оператора запроса SQL, используемого средством чтения данных, с оператором прагмы следующим образом:

PRAGMA read_uncommitted = 1;
SELECT Column1, Column2 FROM MyTable

Теперь можно свободно обновлять и вставлять строки, пока активен считыватель данных. Дополнительную документацию SQLite по общему кешу можно найти здесь.

Обновление:

Более новая версия поставщика данных Devart SQLite теперь поддерживает это улучшенным образом. Чтобы включить общий кеш, можно сделать следующий вызов:

Devart.Data.SQLite.SQLiteConnection.EnableSharedCache();

Можно настроить незафиксированные чтения в строке подключения, например, следующим образом:

Devart.Data.SQLite.SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder();
builder.ReadUncommitted = true;
builder.DateTimeFormat = Devart.Data.SQLite.SQLiteDateFormats.Ticks;
builder.DataSource = DatabaseFilePath;
builder.DefaultCommandTimeout = 300;
builder.MinPoolSize = 0;
builder.MaxPoolSize = 100;
builder.Pooling = true;
builder.FailIfMissing = false;
builder.LegacyFileFormat = false;
builder.JournalMode = JournalMode.Default;
string connectionString = builder.ToString();
person Elan    schedule 21.03.2011