SQLite3 :: BusyException

голоса
35

Запуск Рельсы сайт прямо сейчас с помощью SQLite3.

Примерно раз в 500 запросов или около того, я получаю

ActiveRecord :: StatementInvalid (SQLite3 :: BusyException: база данных заблокирована: ...

Что способ исправить это, что бы минимально инвазивные на мой код?

Я помощью SQLite на данный момент, потому что вы можете хранить БД в системе управления версиями, который делает резервное копирование естественно, и вы можете нажать изменения очень быстро. Тем не менее, это, очевидно, на самом деле не настроен для параллельного доступа. Я мигрируют к MySQL завтра утром.

Задан 17/09/2008 в 00:02
источник пользователем
На других языках...                            


16 ответов

голоса
-8

Я считаю, что это происходит, когда времена сделки вне. Вы действительно должны использовать «реальные» базы данных. Что-то вроде мороси или MySQL. Любая причина, почему вы предпочитаете SQLite над двумя предыдущими вариантами?

Ответил 17/09/2008 в 00:05
источник пользователем

голоса
1

Источник: эта ссылка

- Open the database
db = sqlite3.open("filename")

-- Ten attempts are made to proceed, if the database is locked
function my_busy_handler(attempts_made)
  if attempts_made < 10 then
    return true
  else
    return false
  end
end

-- Set the new busy handler
db:set_busy_handler(my_busy_handler)

-- Use the database
db:exec(...)
Ответил 17/09/2008 в 00:14
источник пользователем

голоса
0

Какие таблицы осуществляется доступ, когда замок встречается?

Есть ли у вас длительные транзакции?

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

Ответил 17/09/2008 в 00:17
источник пользователем

голоса
0

Argh - отрава моего существования в течение последней недели. Sqlite3 блокирует файл базы данных , когда любой процесс записи в базу данных. IE любой UPDATE / INSERT IGNORE типа запрос (также выберите COUNT (*) для какой - либо причины). Тем не менее, она обрабатывает несколько операций чтения просто отлично.

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

И да, его медленно , как ад. Но его также достаточно быстро и правильно , что является хорошим свойством иметь.

Ответил 17/09/2008 в 00:33
источник пользователем

голоса
7

По умолчанию SQLite возвращает немедленно с блокированной, занятой ошибкой, если база данных занят и заблокирована. Вы можете попросить его подождать и продолжать пробовать на некоторое время, прежде чем давать. Обычно это решает проблему, если вы действительно должны 1000s потоков, обращающихся к БД, когда я согласен SQLite бы неуместно.

    // устанавливаем SQLite ждать и повторить попытку до 100мс, если он заблокирован базы данных
    sqlite3_busy_timeout (дБ, 100);
Ответил 18/09/2008 в 17:21
источник пользователем

голоса
53

Вы сказали, что это сайт Rails. Rails позволяет установить тайм-аут SQLite повторов в вашем database.yml конфигурационного файла:

production:
  adapter: sqlite3
  database: db/mysite_prod.sqlite3
  timeout: 10000

Значение тайм-аута задается в миллисекундах. Увеличение его до 10 или 15 секунд, должно уменьшить количество BusyExceptions вы видите в журнале.

Это лишь временное решение, хотя. Если ваш сайт нуждается истинный параллелизм, то вам придется перейти на другую БД двигатель.

Ответил 10/04/2009 в 21:15
источник пользователем

голоса
1

Sqlite может позволить другим процессам ждать, пока ток один не закончил.

Я использую эту линию для подключения, когда я знаю, что может иметь несколько процессов, пытающихся получить доступ к БД SQLite:

Conn = sqlite3.connect ( 'имя_файла', isolation_level = 'эксклюзив' )

Согласно документации Python Sqlite:

Вы можете контролировать, какой вид НАЧАТЬ заявление pysqlite неявно выполняет (или вообще) с помощью параметра isolation_level на подключениях () вызов, или через isolation_level свойства соединений.

Ответил 11/04/2009 в 02:45
источник пользователем

голоса
3

Все эти вещи являются правдой, но это не дает ответа на вопрос, который, скорее всего: почему мой Rails приложения иногда растить SQLite3 :: BusyException в производстве?

@Shalmanese: что такое производство хостинг среды, как? Является ли это на общедоступном хосте? Является ли каталог, который содержит базу данных SQLite на общем ресурсе NFS? (Скорее всего, на общем хозяине).

Эта проблема, вероятно, связаны с явлениями блокировок файлов ж / акции NFS и отсутствие SQLite в параллельности.

Ответил 19/11/2010 в 14:40
источник пользователем

голоса
1

У меня была аналогичная проблема с передним дб: мигрировать. Проблема в том, что рабочий каталог был на долю малого и среднего бизнеса. Я установил ее, скопировав папку к моей локальной машине.

Ответил 24/02/2011 в 23:56
источник пользователем

голоса
2

Только для записи. В одном приложении с Rails 2.3.8, мы выяснили, что Rails игнорирует опцию «тайм-аут» Рифкин Габсбург предложили.

После еще некоторое исследования мы обнаружили , возможно , связанную ошибку в Rails разработчике: http://dev.rubyonrails.org/ticket/8811 . А после еще некоторого исследования мы нашли решение (протестировано с Rails 2.3.8):

Редактировать этот файл ActiveRecord: ActiveRecord-2.3.8 / Библиотека / active_record / connection_adapters / sqlite_adapter.rb

Заменить это:

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction }
  end

с

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction(:immediate) }
  end

И это все! Мы не заметили падение производительности и теперь приложение поддерживает многие другие ходатайства, не нарушая (он ждет тайм-аут). Sqlite приятно!

Ответил 23/05/2011 в 14:46
источник пользователем

голоса
0

Я нашел затор на sqlite3 расширение рубинового и зафиксировать его здесь: имеют пойти с ним и посмотреть, если это исправляет проблему ур.


    https://github.com/dxj19831029/sqlite3-ruby

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

Во всяком случае, некоторые заняты исключением, как ожидается, как описано в самой sqlite3.

Имейте в виду , с этим условием: SQLite занят


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

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

Надеюсь это поможет. :)

Ответил 02/11/2012 в 02:55
источник пользователем

голоса
0

это часто подряд вина из нескольких процессов, имеющих доступ к той же базе данных, то есть если «разрешить только один экземпляр» флаг не был установлен в RubyMine

Ответил 31/01/2013 в 10:38
источник пользователем

голоса
1

Если у вас есть этот вопрос , но увеличивая время ожидания ничего не изменится , то , возможно , есть еще один вопрос параллельности с транзакций, вот это в итоге:

  1. Начните транзакцию (aquires с SHARED замка)
  2. Прочитайте некоторые данные из БД (мы все еще используем SHARED замок)
  3. Между тем, другой процесс начинает транзакцию и записи данных (приобретение Зарезервированного замка).
  4. Затем вы пытаетесь писать, вы теперь пытаетесь запросить Зарезервированный замок
  5. SQLite вызывает исключение SQLITE_BUSY немедленно (indenpendently вашего тайм - аута) , потому что ваш предыдущий читает больше не может быть точным временем он может получить Зарезервированные замок.

Один из способов исправить это патч active_recordSQLITE адаптера aquire в Зарезервированный замке непосредственно в начале сделки путем наложения :immediateопции для водителя. Это позволит снизить производительность немного, но , по крайней мере , все ваши транзакции будут выполнять свой тайм - аут и происходят один за другим. Вот как это сделать с помощью prepend(Ruby 2.0+) поместить это в инициализаторе:

module SqliteTransactionFix
  def begin_db_transaction
    log('begin immediate transaction', nil) { @connection.transaction(:immediate) }
  end
end

module ActiveRecord
  module ConnectionAdapters
    class SQLiteAdapter < AbstractAdapter
      prepend SqliteTransactionFix
    end
  end
end

Подробнее здесь: https://rails.lighthouseapp.com/projects/8994/tickets/5941-sqlite3busyexceptions-are-raised-immediately-in-some-cases-despite-setting-sqlite3_busy_timeout

Ответил 01/10/2014 в 19:35
источник пользователем

голоса
2
bundle exec rake db:reset

Он работал для меня это сбросит и показать отложенную миграцию.

Ответил 13/02/2015 в 05:09
источник пользователем

голоса
0

Попробуйте выполнить следующие действия, оно может помочь:

ActiveRecord::Base.connection.execute("BEGIN TRANSACTION; END;") 

От: Ruby: SQLite3 :: BusyException: база данных заблокирована:

Это может прояснить любую сделку, подняв систему

Ответил 13/02/2015 в 05:22
источник пользователем

голоса
1

Большинство ответов на Rails, а не сырой рубин, и ФОС вопрос к рельсам, что прекрасно. :)

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

После Instancing соединение, вы можете установить это следующим образом:

db = SQLite3::Database.new "#{path_to_your_db}/your_file.db"
db.busy_timeout=(15000) # in ms, meaning it will retry for 15 seconds before it raises an exception.
#This can be any number you want. Default value is 0.
Ответил 13/12/2017 в 11:11
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more