2010-05-05 2 views
7

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

+0

SQLite заявляет, что вы не можете делиться одним и тем же объектом по потокам. вы уверены, что не делаете этого? – Andrey

+0

@ Andrey: можете ли вы разместить ссылку на это сообщение? Когда я недавно прочитал об этом, SQLite говорит, что он потокобезопасен *, хотя * они считают, что потоки злы, и что вы не должны использовать SQLite в многопоточной программе, если только к нему не обращается только один поток. Но технически, он должен быть потокобезопасным. По крайней мере, это то, что я вспоминаю. – Dave

+0

@Dave: http://www.sqlite.org/cvstrac/wiki?p=MultiThreading ключевая фраза: под «threadsafe» мы подразумеваем, что вы можете использовать разные соединения базы данных SQLite в разных потоках одновременно. – Andrey

ответ

8

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

Затем каждая нить переходит вставить количество записей, скажем 1000. проблема вы столкнетесь это следующее: один поток получит управление над базой данных, установив замок на файл. Это нормально, но остальные из нитей будут продолжать сбой для каждой попытки INSERT, если активна блокировка . (reference)

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

Если вы хотите, чтобы избежать неисправной-то время автоподстройки вопрос вы можете проверить флаг 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; 

same reference

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

0

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

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

2

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

(это означает, что мы используем System.Data.SQLite.Чистая библиотека)

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

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

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

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

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

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

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

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

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