Rails разрешает двойной пост-запрос для блокировки базы данных? - PullRequest
0 голосов
/ 07 марта 2012

Я использую Valums Ajax Uploader , чтобы создать приятный пользовательский интерфейс для загрузки фотографий в мое приложение rails. Одна из проблем - иногда он отправляет запросы Post слишком близко друг к другу, а затем они вызывают исключение блокировки базы данных, которое на время приводит к сбоям при загрузке.

Вот пример журнала:

Started POST "/photos?authenticity_token=WPJo8nnJ3KSoG9O%2B%2Flz%2BPbvdtX8cmbEaVB8TidnLx5Y%3D&qqfile=IMG_0417.JPG" for 127.0.0.1 at 2012-03-06 22:39:25 -0600
Processing by PhotosController#create as HTML
  Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x007f9e5529f518 @original_filename="IMG_0417.JPG", @content_type="application/octet-stream", @headers=nil, @tempfile=#<File:/var/folders/mf/06zfbjcn63j6p2rqvt6tc77c0000gn/T/raw-upload.20120306-53350-13pew0o>>, "authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0417.JPG"}
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1


Started POST "/photos?authenticity_token=WPJo8nnJ3KSoG9O%2B%2Flz%2BPbvdtX8cmbEaVB8TidnLx5Y%3D&qqfile=IMG_0418.JPG" for 127.0.0.1 at 2012-03-06 22:39:30 -0600
Processing by PhotosController#create as HTML
  Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x007fcfddd8d268 @original_filename="IMG_0418.JPG", @content_type="application/octet-stream", @headers=nil, @tempfile=#<File:/var/folders/mf/06zfbjcn63j6p2rqvt6tc77c0000gn/T/raw-upload.20120306-53383-1plhm8r>>, "authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0418.JPG"}
 "authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0418.JPG"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
   (0.1ms)  begin transaction
  CACHE (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
  SQL (0.6ms)  INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["city", nil], ["comments_updated_at", nil], ["context_id", nil], ["country", nil], ["created_at", Tue, 06 Mar 2012 22:39:37 CST -06:00], ["custom_title", nil], ["description", nil], ["featured", false], ["flagged", nil], ["focus_id", nil], ["full_downloads", 0], ["height", 2304], ["image", "admin_tester_630cm1715.JPG"], ["lat", nil], ["lng", nil], ["place", nil], ["presentation_downloads", 0], ["state", nil], ["status", "batch"], ["updated_at", Tue, 06 Mar 2012 22:39:37 CST -06:00], ["user_id", 1], ["width", 3072]]
  SQL (0.2ms)  UPDATE "users" SET "photos_count" = COALESCE("photos_count", 0) + 1 WHERE "users"."id" = 1
   (0.1ms)  begin transaction
  CACHE (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
  SQL (5064.0ms)  INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["city", nil], ["comments_updated_at", nil], ["context_id", nil], ["country", nil], ["created_at", Tue, 06 Mar 2012 22:39:43 CST -06:00], ["custom_title", nil], ["description", nil], ["featured", false], ["flagged", nil], ["focus_id", nil], ["full_downloads", 0], ["height", 2304], ["image", "admin_tester_630cm171b.JPG"], ["lat", nil], ["lng", nil], ["place", nil], ["presentation_downloads", 0], ["state", nil], ["status", "batch"], ["updated_at", Tue, 06 Mar 2012 22:39:43 CST -06:00], ["user_id", 1], ["width", 3072]]
SQLite3::BusyException: database is locked: INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
   (0.3ms)  rollback transaction
SQLite3::BusyException: cannot rollback transaction - SQL statements in progress: rollback transaction
Completed 500 Internal Server Error in 17749ms

ActiveRecord::StatementInvalid (SQLite3::BusyException: cannot rollback transaction - SQL statements in progress: rollback transaction):
  app/controllers/photos_controller.rb:29:in `create'
  app/uploaders/flash_session_cookie_middleware.rb:16:in `call'

Очевидно, что это не хорошо, если это происходит, когда один пользователь загружает несколько изображений, это не соответствует производственным стандартам. Итак, как вы это исправите? Как правильно обрабатывать загрузку и обработку такого файла, чтобы параллелизм не был большой проблемой?

1 Ответ

0 голосов
/ 07 марта 2012

Возможно, вы захотите перейти с SQLite, если у вас есть несколько процессов, обращающихся к одной базе данных. Хотя это поддерживается SQLite, он требует блокировки всей базы данных, чтобы избежать повреждения данных при фиксации. Это в общих чертах объясняется в FAQ по SQLite .

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

Хорошей новостью является то, что преобразование из SQLite в MySQL или Postgres обычно очень просто.

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

...