ruby-on-rails - 多个请求同时出现重复输入错误
问题描述
我正在对我的代码进行测试,它可以毫无问题地处理单个请求,但是当我尝试同时针对多个请求发送它时,我遇到了重复错误。我使用 MySQL 作为数据库。
模型
class Playtime < ApplicationRecord
validates :local_id, uniqueness: true, allow_blank: true
end
控制器
由此
def create
begin
if !Playtime.where(local_id: params[:local_id]).exists?
@playtime = Playtime.create!(playtime_params)
json_response(@playtime.local_id,true)
else
json_response(params[:local_id], true)
end
rescue ActiveRecord::RecordInvalid => invalid
json_response(invalid.record.errors.full_messages.first,false)
end
end
对此,我认为它会解决这个问题。
def create
begin
if !Playtime.where(local_id: params[:local_id]).exists?
@playtime = Playtime.create(playtime_params)
if @playtime.valid?
json_response(@playtime.local_id,true)
else
json_response(params[:local_id], true)
end
else
json_response(params[:local_id], true)
end
rescue ActiveRecord::RecordInvalid => invalid
json_response(invalid.record.errors.full_messages.first,false)
end
end
但同样的错误。
我的请求。
curl -X POST \
http://localhost:3000/events/playtime \
-H 'Content-Type: application/json' \
-H 'Postman-Token: b4a636e9-5802-446f-9770-692895ebdbfd' \
-H 'cache-control: no-cache' \
-d '{
"local_id": "664278-153"
}'&
curl -X POST \
http://localhost:3000/events/playtime \
-H 'Content-Type: application/json' \
-H 'Postman-Token: b4a636e9-5802-446f-9770-692895ebdbfd' \
-H 'cache-control: no-cache' \
-d '{
"local_id": "664278-153"
}'
错误未通过救援。
ActiveRecord::RecordNotUnique (Mysql2::Error: Duplicate entry '664278-153' for key 'index_playtimes_on_local_id': INSERT INTO `playtimes`
解决方案
问题在这里:
if !Playtime.where(local_id: params[:local_id]).exists?
# ⇒ SWITCH OF THE CONTEXT, RECORD CREATED BY ANOTHER PROCESS
@playtime = Playtime.create!(playtime_params)
基本上,检查通过,然后在create 进入数据库之前,处理同时请求的其他进程已经在数据库中创建了记录。
最常见的方法是使用Optimistic Locking和救援StaleObjectError,但在这里你已经对字段进行了限制,所以它会更容易:
def create
# no need to begin here, you might rescue the whole function body
@playtime = Playtime.create!(playtime_params)
json_response(@playtime.local_id, true)
rescue ActiveRecord::RecordNotUnique
# record is already there, ok
json_response(params[:local_id], true)
rescue ActiveRecord::RecordInvalid => invalid
# params are invalid, report
json_response(invalid.record.errors.full_messages.first, false)
end
旁注:我们通常提供带有错误报告的 HTTP 错误代码,您的代码目前可能200 OK
在“无效”响应中提供服务。
推荐阅读
- java - 将堆栈顶部放置在链接链的末尾而不是开头
- ssas - 将属性绑定到 NameColumn 并将属性绑定到 KeyColumn 的目的是什么?
- linux - 使用 openvpen 而不是 openvpn3 连接到 staging vpn
- django - Django项目中docker-compose中的Postgres连接问题
- amazon-web-services - 调用 SSH 时 Shell 脚本停止
- elasticsearch - Elasticsearch 对过滤条件组进行“或”搜索
- c++ - 部分模板特化:std::allocator_traits?
- homebrew - 尝试在 MacOS 上更新 Homebrew 但收到错误消息“LibreSSL 错误”
- json - 阅读 REST API JSON 回复
- leaflet - 如何以编程方式获取 PixiOverlay 标记并通过绘制的边界获取它们的属性