2009-06-30 3 views
15

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

+0

По крайней мере, вы могли бы пометить свой вопрос на соответствующем языке программирования. –

+0

Yeap, или укажите, что вам нужна языковая агностическая платформа - агностик-все-агностический подход. – sharptooth

+1

Я бы попробовал снова спросить, не «покажи мне код» ... –

ответ

13

Во-первых, избегайте одновременного доступа к файлам базы данных sqlite. Параллелизм является одним из слабых мест SQLite, и если у вас есть очень параллельное приложение, подумайте об использовании другого механизма базы данных.

Если вы не можете избежать параллелизма или падение SQLite, обернуть WRITE сделок в BEGIN IMMEDIATE; ... END;. Режим транзакции по умолчанию в sqlite равен DEFERRED, что означает, что блокировка получена только при первой попытке реальной записи. С транзакциями IMMEDIATE замок немедленно приобретается, или вы сразу получаете SQLITE_BUSY. Когда кто-то держит блокировку в базе данных, другие попытки блокировки приведут к SQLITE_BUSY.

Работа с SQLITE_BUSY - это то, что вам нужно решить самостоятельно. Для многих приложений, ожидающих второго или двух, а затем повторных попыток работы все в порядке, отказ после n неудачных попыток. Есть помощники API sqlite3, которые делают это легко, например. sqlite3_busy_handler() и sqlite3_busy_timeout(), но это также можно сделать вручную.

Вы также можете использовать синхронизацию уровня ОС, чтобы получить блокировку мьютекса в базе данных, или использовать обмен сообщениями между потоками/межпроцессорными сообщениями уровня OS, чтобы сигнализировать, когда один поток выполняется для доступа к базе данных.

+0

Я знаю, что нужно использовать транзакции в рамках одного процесса. Однако моя ситуация заключается в том, что у меня есть несколько процессов, в отличие от нескольких потоков, одновременно доступ к одной и той же БД. Действительно ли транзакции SQLite обрабатывают такой параллелизм??!? – 2009-06-30 14:10:24

+0

@Tom: Да, в слое для портирования ОС, специфичном для ОС sqlite3, есть функция блокировки, которая работает во всех процессах. См. Http://www.sqlite.org/lockingv3.html для более – laalto

+1

DEFERRED на самом деле означает, что база данных не заблокирована (до тех пор, пока к ней не будет доступ через чтение или запись после инструкции BEGIN (да, она должна блокировать читать). IMMEDIATE означает, что база данных блокируется сразу же после выполнения «НАЧАТЬ НЕМЕДЛЕННЫЙ ПЕРЕВОД». См. Http://www.sqlite.org/lang_transaction.html –

2

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

В качестве альтернативы вы можете использовать синхронизацию ОС - mutex на MS Windows или что-то подобное на других ОС. Этот процесс попытается получить мьютекс, и если кто-то еще его удерживает, процесс будет заблокирован до тех пор, пока другой процесс не завершит операцию и не выпустит мьютекс. Следует соблюдать осторожность, чтобы предотвратить случаи, когда процесс получает мьютекст, а затем никогда не выпускает его.

+1

Хм, не SQLite предоставляют блокировки для защиты доступа к файлу базы данных? – 2009-06-30 13:18:26

0

The SQLite FAQ о точно this

+1

Я прочитал этот FAQ, прежде чем я разместил здесь свой вопрос. Я должен был, конечно, сказать (это был второй урок, который я узнал сегодня). Я не мог точно понять, что они имели в виду. Должен ли я сам обрабатывать все блокирующие вещи, или SQLite поддерживает его? «Когда какой-либо процесс хочет писать, он должен заблокировать весь файл базы данных на время его обновления, но обычно это занимает всего несколько миллисекунд. Другие процессы просто ждут, когда автор закончит, а затем продолжит свою деятельность». Это потребует определенных усилий для реализации этого для меня. – 2009-06-30 14:15:29

+0

Не только это утомительно, но и склонна к ошибкам. И я надеюсь, что SQLite получит необходимую поддержку, и в этом случае мне интересно, какие функции я должен использовать. В качестве примечания, я думаю, что документация SQLite слишком сдержанна, когда дело доходит до примеров с исходным кодом ... – 2009-06-30 14:18:04

+0

https://meta.stackexchange.com/questions/225370/your-answer-is-in-another- замок-когда-это-ан-ответ-не-ан-ответ –

2

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

В SQLite вы используете

BEGIN TRANSACTION

COMMIT TRANSACTION

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

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

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

Смежные вопросы