Rails在唯一索引和validates_uniqueness_of中有什么区别

mru*_*ult 5 postgresql indexing ruby-on-rails

首先,任何人都可以解释独特的索引如何在数据库中工作?

假设我有一个带有a的用户模型,name column我在其unique index上添加了一个但是在模型中(user.rb)我presence在该name字段上只有一个验证器.

所以现在当我尝试创建两个具有相同名称的用户时,我得到了PGError

重复键值违反唯一约束"index_users_on_name"

所以它看起来像unique index工作一样uniqueness validator(?)

如果是这样那么外键呢?

可以说我有Post与之belongs_to :user关联的模型User has_many :posts.和外键user_idposts table具有唯一索引.然后多个帖子不能相同user_id.

有人可以解释一下unique index有效吗?

我使用Ruby 2.0.0在Rails 4上.

LHH*_*LHH 17

以下是unique index和validates_uniqueness_of之间的区别

这是一个补丁,用于使ActiveRecord能够识别数据库生成的唯一约束违规错误.例如,它在不声明validates_uniqueness_of的情况下进行以下工作:

create_table "users" do |t|
  t.string   "email",   :null => false
end
add_index "users", ["email"], :unique => true

class User < ActiveRecord::Base
end

User.create!(:email => 'abc@abc.com')
u = User.create(:email => 'abc@abc.com')
u.errors[:email]
=> "has already been taken"
Run Code Online (Sandbox Code Playgroud)

好处是速度,易用性和完整性 -

速度

使用这种方法,您无需进行数据库查找以在保存时检查唯一性(错过索引时有时会非常慢 - https://rails.lighthouseapp.com/projects/8994/tickets/2503 -validate ...).如果您真的关心验证唯一性,那么无论如何都必须使用数据库约束,因此无论如何数据库都将验证唯一性,这种方法会删除额外的查询.检查索引两次对于DB来说不是问题(第二次缓存它),但是从应用程序中保存数据库往返是一个很大的胜利.

便于使用

鉴于您必须具有真正唯一性的数据库约束,这种方法将使所有内容在数据库约束到位后自动发生.如果您愿意,仍然可以使用validates_uniqueness_of.

完整性

validates_uniqueness_of一直是一个hack - 它无法正确处理竞争条件并导致必须使用有点冗余的错误处理逻辑处理的异常.(请参阅http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMe中的 "并发性和完整性"部分.)

validates_uniqueness_of不足以确保值的唯一性.原因是在生产中,多个工作进程可能导致竞争条件:

  1. 两个并发请求尝试创建具有相同名称的用户(我们希望用户名是唯一的)

  2. 两个工作进程在服务器上接受请求,这两个进程现在将并行处理它们

  3. 两个请求都扫描users表并查看该名称是否可用

  4. 两个请求都通过验证并创建具有看似可用名称的用户

为了更清楚地理解,请检查一下

如果为列创建唯一索引,则意味着您可以保证该表不会有多个具有该列相同值的行.在模型中仅使用validates_uniqueness_of验证不足以强制执行唯一性,因为可能有并发用户尝试创建相同的数据.

想象一下,两个用户尝试使用您在用户模型中添加validates_uniqueness_of:email的同一电子邮件注册帐户.如果他们同时点击"注册"按钮,Rails会在用户表中查找该电子邮件并回复一切正常,并且可以将记录保存到表中.然后Rails会使用相同的电子邮件将两条记录保存到用户表中,现在您有一个非常糟糕的问题需要处理.

为避免这种情况,您还需要在数据库级别创建唯一约束:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      ...
    end

    add_index :users, :email, unique: true
  end
end
Run Code Online (Sandbox Code Playgroud)

因此,通过创建index_users_on_email唯一索引,您将获得两个非常好的好处.数据完整性和良好性能,因为唯一索引往往非常快.

如果在posts表中为user_id设置unique:true,则不允许输入具有相同user_id的重复记录.