SQLite многопроцессорный доступ - PullRequest
7 голосов
/ 05 мая 2010

Мы используем SQLite в многопоточных и многопоточных приложениях. Файлы базы данных SQLite шифруются с использованием встроенного шифрования SQLite. FAQ утверждает, что SQLite должен иметь возможность управлять многопроцессорным доступом с использованием механизма блокировок. Мы испытываем странную проблему: Когда многие потоки обращаются к одному и тому же файлу базы данных, иногда возникают нарушения ограничений, более конкретно - поле с уникальным ограничением получает повторяющиеся значения после вызова оператора «вставьте или замените». Это часто случается сейчас, когда мы используем шифрование. До того, как мы начали использовать шифрование SQLite, мы не замечали такого поведения. Есть ли какие-либо конкретные известные проблемы с этим?

Ответы [ 3 ]

9 голосов
/ 06 мая 2010

Хотя SQLite «поточно-ориентированный», вы все равно не можете одновременно изменить базу данных:

Затем каждый поток продолжает вставлять количество записей, скажем, 1000. проблема, с которой вы столкнетесь, следующее: один поток получит контроль через базу данных, установив блокировку на файл. Это хорошо, но остальное из потоков будет продолжать сбой за каждую попытку ВСТАВИТЬ, пока Блокировка активна. ( ссылка )

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

Если вы хотите избежать проблемы сбоя при блокировке, вы можете проверить флаг SQLITE_BUSY:

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

  while (continueTrying) {
    retval = sqlite_exec(db, sqlQuery, callback, 0, &msg);
    switch (retval) {
      case SQLITE_BUSY:
        Log("[%s] SQLITE_BUSY: sleeping fow a while...", threadName);
        sleep a bit... (use something like sleep(), for example)
        break;
      case SQLITE_OK:
        continueTrying = NO; // We're done
        break;
      default:
        Log("[%s] Can't execute \"%s\": %s\n", threadName, sqlQuery, msg);
        continueTrying = NO;
        break;
    }
  }

  return retval;

та же ссылка

Держу пари, что ваше нарушение ограничения не имеет ничего общего с многопоточностью, поэтому не могли бы вы опубликовать фактическое полученное нарушение ограничения (или пример, соответствующий www.sscce.org ) .

2 голосов
/ 07 мая 2010

Спасибо за все ваши комментарии!

(следует отметить, что мы используем библиотеку System.Data.SQLite .Net)

Тем временем мы сделали еще несколько тестов, и вот результаты

===============

Мы создали тестер, который выполняет следующие функции: - создать таблицу с несколькими полями. Одно из полей - nvarchar (255) - имеет уникальный индекс: «создать уникальный индекс IX_MyKey on Table (MyKey)» - запустить много одинаковых процессов (25) одновременно - у каждого процесса есть ключ (строка, представляющая число 1-25) - У каждого процесса есть один (основной) поток, выполняющий в течение 30 секунд в цикле:

прочитайте запись, где MyKey = @ MyKey (ключ процесса) получить значение числового поля записать обратно «значение + 1» в то же поле той же записи «вставить или заменить ... где MyKey = @ MyKey»

===============

  • Когда мы делаем все вышеизложенное с использованием библиотеки System.Data.SQLite без шифрования - все работает как положено (включая блокировки, которые замедляют доступ к базе данных при увеличении количества процессов)

  • Когда мы используем шифрование (путем установки пароля для базы данных), ограничение индекса уникальное «нарушено» - появляются записи с одинаковым значением MyKey

===============

Значит, проблема как-то связана с шифрованием ...

1 голос
/ 06 мая 2010

Убедитесь, что вы не разделяете соединения между потоками - каждый поток должен создавать свое собственное соединение. И убедитесь, что вы заключаете свои запросы в транзакции.

Я использую System.Data.Sqlite с открытым исходным кодом (http://sqlite.phxsoftware.com/) Оболочка ADO.Net, которая является поточно-ориентированной, если вы не разделяете соединения между потоками. Она также легко шифрует базу данных, как описано здесь: http://sqlite.phxsoftware.com/forums/t/130.aspx (просто установите свойство пароля). Поищите на его форуме информацию о том, как он конкретно использует Microsoft Crypto API для шифрования, и подробности о безопасности потоков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...