我正在对我的代码进行测试,它可以在单个请求上正常工作,但是当我尝试同时在多个请求上发送它时,我遇到了重复错误。我正在使用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`
答案 0 :(得分:3)
问题在这里:
if !Playtime.where(local_id: params[:local_id]).exists?
# ⇒ SWITCH OF THE CONTEXT, RECORD CREATED BY ANOTHER PROCESS
@playtime = Playtime.create!(playtime_params)
基本上,检查通过了,然后之前创建到数据库中的另一个处理并发请求的进程已在数据库中创建了记录。
最常见的荒谬方法是使用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
。