我有以下代码块:
unless User.exist?(...)
begin
user = User.new(...)
# Set more attributes of user
user.save!
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
# Check if that user was created in the meantime
user = User.exists?(...)
raise e if user.nil?
end
end
原因是,你可能猜到了,多个进程可能同时调用这个方法来创建用户(如果它不存在的话),所以当第一个进入块并开始初始化一个新用户时,设置属性并最终调用 save!,用户可能已经创建。在这种情况下,我想再次检查用户是否存在,并且仅在仍然不存在时引发异常(=如果同时没有其他进程创建它)。
问题是,保存时会定期引发 ActiveRecord::RecordInvalid 异常!并没有从救援区救出。有任何想法吗?
编辑:
好吧,这很奇怪。我肯定错过了什么。我根据 Simone 的提示重构了代码,如下所示:
unless User.find_by_email(...).present?
# Here we know the user does not exist yet
user = User.new(...)
# Set more attributes of user
unless user.save
# User could not be saved for some reason, maybe created by another request?
raise StandardError, "Could not create user for order #{self.id}." unless User.exists?(:email => ...)
end
end
现在我得到了以下异常:
ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry 'foo@bar.com' for key 'index_users_on_email': INSERT INTO `users` ...
扔在写着“除非user.save”的那一行。这个怎么可能?Rails 认为可以创建用户,因为电子邮件是唯一的,但是 Mysql 唯一索引阻止了插入?那可能性有多大?又该如何避免呢?