2010-10-15 7 views
6

Есть ли известная проблема с SQLite, дающая ошибку «база данных заблокирована» для второго запроса в одной транзакции при использовании Perl DBD :: SQLite? Сценарий: Linux, Perl DBI, AutoCommit => 0, подпрограмма с двумя блоками кода (с использованием блоков для локализации имен переменных). В первом блоке кода дескриптор запроса создается командой prepare() в инструкции select, он выполняется(), и блок закрыт. Второй код блокирует другой дескриптор запроса, создается путем подготовки к оператору обновления, а часто (30% времени) SQLite/DBI дает ошибку блокировки базы данных на этом этапе. Я думаю, что ошибка происходит во время подготовки(), а не во время выполнения().Почему SQLite дает «базу данных заблокирован» для второго запроса в транзакции при использовании Perl DBD :: SQLite?

Моя работа заключается в фиксации после первого запроса. (Вызов завершения первого запроса не помог). Я предпочитаю не совершать несколько причин, связанных с элегантностью и эффективностью. Исходный код работал отлично в течение многих лет с Postgres в качестве базы данных. Я пробовал sqlite_use_immediate_transaction без эффекта.

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

+0

Можете ли вы показать нам свой небольшой тестовый пример, который демонстрирует проблему? –

ответ

6

Не имеет отношения к этому в любом случае: Transaction and Database Locking от DBD::SQLite perldoc?

Сделка по AutoCommit или begin_work хорошая и удобная, но иногда вы можете получить раздражающую ошибку «база данных заблокирована». Обычно это происходит, когда кто-то начинает транзакцию и пытается записать в базу данных, пока другой человек читает из базы данных (в другой транзакции). Вы можете быть удивлены, но SQLite не блокирует базу данных, когда вы только начинаете обычную (отложенную) транзакцию, чтобы максимизировать параллелизм. Он резервирует блокировку, когда вы выдаете инструкцию для записи, но пока вы на самом деле не пытаетесь написать с помощью инструкции commit, она позволяет другим людям читать из базы данных. Тем не менее, чтение из базы данных также требует совместной блокировки, и это предотвращает предоставление вам исключительной блокировки, которую вы зарезервировали, таким образом вы получаете ошибку «база данных заблокирована», а другие люди получат ту же ошибку, если они попытаются написать потом, так как у вас все еще есть ожидающая блокировка. busy_timeout в этом случае не помогает.

Чтобы избежать этого, введите тип транзакции явно. Вы можете начать немедленную транзакцию (или начать эксклюзивную транзакцию) для каждой транзакции или установить атрибут обработки базы данных sqlite_use_immediate_transaction в true (начиная с 1.30_02), чтобы всегда использовать немедленную транзакцию (даже если вы просто используете begin_work или отключите AutoCommit.) ,

my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", { 
    sqlite_use_immediate_transaction => 1, 
}); 

Обратите внимание, что это работает только тогда, когда все соединения используют один и тот же (не отсроченный) сделки. См. http://sqlite.org/lockingv3.html для информации о блокировке.