Mysql Rails验证唯一性在并发输入上失败

Mysql Rails验证唯一性在并发输入上失败,mysql,ruby-on-rails,Mysql,Ruby On Rails,我有一个Ticket模型,在字符串属性Ticket\u number validates :ticket_number, uniqueness: true 这是车票号的输入代码 <%= f.number_field :ticket_number, :value => @ticket.ticket_number || (Ticket.exists? ? Ticket.maximum(:ticket_number).next) : 1 , :class => 'form-cont

我有一个
Ticket
模型,在字符串属性
Ticket\u number

validates :ticket_number, uniqueness: true
这是
车票号的输入代码

<%= f.number_field :ticket_number, :value => @ticket.ticket_number || (Ticket.exists? ? Ticket.maximum(:ticket_number).next) : 1 , :class => 'form-control' %>
@ticket.ticket_number | |(ticket.exists→ticket.maximum(:ticket_number).next):1,:class=>'表单控件'>
验证似乎如预期的那样工作,但是当我们部署应用程序时,可能有多个用户同时输入
票证
,这不应该引起问题(对吗?)我们在数据库(MySQL)中发现了重复的记录(相同的票证号)


到目前为止,在总共600多张门票中,这只发生过一次,但为什么以及如何防止这种情况发生?

这是非常罕见的,你可能非常不幸,因为它发生了,这是可能的

阅读:

考虑以下几点: 用户提交表单

  • 用户提交表单
  • Rails检查数据库中是否存在用户A的现有ID-未找到
  • 用户B提交表单
  • Rails检查数据库中是否存在用户B的现有ID-未找到
  • Rails为用户保存一条记录
  • Rails保存用户B记录
所有这些都必须在毫秒内发生,但从技术上讲是可能的


我建议在数据库级别(主键)添加一个约束。

@Yule-answer非常有用,它解释了为什么会发生这种情况,并且添加数据库级别的约束将防止这种情况发生

这将抛出一个
ActiveRecord::RecordNotUnique
exseption,我当然不希望用户看到它,因此下面就是如何应用@Yule建议的解决方法:

  • 在属性上添加索引
    add_index(:tickets, :ticket_number, :unique => true)
    


    当然,控制器的更新操作也应该这样做

    谢谢你的提示。我一直面临着一个类似的问题,但我担心我无法在数据库级别设置唯一的索引。我还有别的选择吗?谢谢
    def create
     @ticket = Ticket.new(ticket_params)
     if @ticket.save
       flash[:success] = 'Ticket was successfully created.'
     else
       render action: 'new'
     end
     #catch the exception
     rescue ActiveRecord::RecordNotUnique
       flash[:danger] = 'The ticket number you entered is already taken !'
       render action: 'new'
    end