2015-02-12 4 views
3

Я использую SQLite (System.Data.SQLite.dll) в многопоточной программе для Windows. Я использую этот код:Выполняется ли SQLiteConnection.BeginTransaction при блокировке базы данных?

using (var cn = new SQLiteConnection(connectionString)) 
{ 
    cn.Open(); 
    using (var tx = cn.BeginTransaction()) 
    { 
      // do some work here 

     tx.Commit(); 
    } 
} 

Я Подчеркивая программу, используя 8 параллельных потоков записи в базу данных одновременно. Иногда я вижу это сообщение в окне вывода Visual Studio:

SQLite error (517): statement aborts at 1: [BEGIN IMMEDIATE] database is locked 

Но исключение не выбрасывается вообще, и все работает так, как ожидалось. Поэтому я думаю, что SQLConnection.BeginTrasaction() повторяет попытку, когда получает базу данных SQLite (517), заблокирована.

Я прав?

Если да, сколько раз SQLConnection.BeginTransaction повторяет попытку перед выбросом исключения. Это настраивается?

ответ

3

Это обрабатывается BUSY TIMEOUT:

PRAGMA busy_timeout;
PRAGMA busy_timeout = миллисекунды;

Запросить или изменить настройку таймаута занятости. Эта прагма является альтернативой языку интерфейса sqlite3_busy_timeout(), который доступен как прагма для использования с языковыми связями, которые не обеспечивают прямой доступ к sqlite3_busy_timeout().

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

Интервал тайм-аута определяется по умолчанию 30 секунд в SQLite.dll. Оказывается, вы не можете изменить это, только путем вызова небезопасной функции C.

От SQLite C Interface:

INT sqlite3_busy_timeout (sqlite3 *, Int мс);

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

+1

Спасибо, что объясняет вещи –

+0

Что случилось с BusyTimout собственности? Будет ли это в следующей версии System.Data.SQLite ?. PRAGMA busy_timeout возвращает 0 в моей программе. Что здесь происходит? Использует ли System.Data.SQLite sqlite3_busy_handler https://www.sqlite.org/c3ref/busy_handler.html? –

+0

Оказывается, он не указан внутри Sqlite.dll. Это было в другой библиотеке с открытым исходным кодом. Похоже, вы не можете явно установить его вообще: / –

1

Я, наконец, нашел его в исходном коде System.Data.SQLite.dll.

метод SQLite3.Prepare (которым вызывается перед выполнением любой команды) имеет следующий код в нем:

while ((n == SQLiteErrorCode.Schema || n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy) && retries < 3) 
{ 
    try 
    ... 

Так, System.Data.SQLite повторит любую команду до 3 раз, прежде чем выбросить исключение ,

EDIT:

SQLite3.Приготовьте метод имеет этот интересный фрагмент кода, который нуждается в пояснениях:

else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy) // Locked -- delay a small amount before retrying 
    { 
    // Keep trying 
    if (rnd == null) // First time we've encountered the lock 
     rnd = new Random(); 

    // If we've exceeded the command's timeout, give up and throw an error 
    if ((uint)Environment.TickCount - starttick > timeoutMS) 
    { 
     throw new SQLiteException(n, GetLastError()); 
    } 
    else 
    { 
     // Otherwise sleep for a random amount of time up to 150ms 
     System.Threading.Thread.Sleep(rnd.Next(1, 150)); 
    } 
    } 

Обратите внимание, что заблокирован и занята erros не увеличивать число попыток счетчика, поэтому Приготовьте метод будет продолжать соединяться до времени ожидания команды, пока не истечет.

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

Configurable number of retries and sleep time of SQLite3.Prepare