Rails允许双帖请求锁定数据库?

时间:2012-03-07 04:48:49

标签: ruby-on-rails post file-upload concurrency

我正在使用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 :(得分:0)

如果您有多个进程访问同一个数据库,您可能希望从SQLite迁移。虽然SQLite支持这一点,但它确实需要锁定整个数据库,以避免在提交期间破坏数据。这在SQLite FAQ中粗略地解释。

虽然SQLite非常适合小规模数据库和开发工作,但对于看到大量写入活动的生产级应用程序而言,这可能不是最佳选择。

好消息是从SQLite转换为MySQL或Postgres通常非常简单。

由于SQLite处理锁定的方式,您可能会遇到某种死锁情况。你的上传需要花费这么长的时间才能处理,这也很奇怪。