在竞争激烈期间,我遇到了在下表中查找/创建特定记录的意外情况。我相信数据库中存在竞争条件。
create_table "business_objects", force: :cascade do |t|
t.string "obj_id", limit: 255
t.string "obj_type", limit: 255
t.datetime "created_at", precision: 6, null: false
end
add_index "business_objects", ["obj_type", "obj_id"], name: "index_business_objects_on_obj_type_and_obj_id", unique: true, using: :btree
违规代码:
def find_or_create_this
attributes = self.attributes.slice('obj_id', 'obj_type')
BusinessObject.find_or_create_by!(attributes)
rescue ActiveRecord::RecordNotUnique
BusinessObject.find_by!(attributes)
end
find_or_create_by!
中的查找返回 nil 并触发 create!
,这引发了 ActiveRecord::RecordNotUnique
错误。救援 block 捕获它并尝试找到导致非唯一错误的记录,但它也返回 nil。我的期望是,如果违反索引唯一性约束,则应将记录提交给表。我错过了什么?
最佳答案
要回答我自己的问题,请研究 MySQL 的事务隔离级别.将有问题的代码包装在事务 block 中并修改隔离级别。
选项是:
- 阅读未提交
- 可序列化
- 可重复读
已提交阅读
def find_or_create_this attributes = self.attributes.slice('obj_id', 'obj_type') ActiveRecord::Base.transaction(isolation: :read_committed) 做 BusinessObject.find_or_create_by!(属性) 结尾 救援 ActiveRecord::RecordNotUnique ActiveRecord::Base.transaction(isolation: :read_committed) 做 BusinessObject.find_by!(属性) 结尾 结束
关于mysql - 异常的 ActiveRecord 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40599861/