Rails 向大家请教一个关于 Rails 的验证的问题

shangrenzhidao · 2014年09月12日 · 最后由 shangrenzhidao 回复于 2014年09月15日 · 3170 次阅读

Rails 可以在 ActiveRecord 中加入唯一性的验证

我看书,上面说这种方式也会产生问题,也会向数据库插入两条一样的数据,在数据库层再加一次唯一性校验没错

但是我不明白的是:“为什么 rails 不能避免这种重复插入记录的情况呢,它的校验不是和数据库中的记录作对比吗?”,难道和多线程有关系?

希望知道的朋友能帮我指点迷津。

并发的缘故?毕竟 Rails 层验证,读取数据库是又时间的嘛。

#1 楼 @small_fish__ 并非是由什么造成的

#2 楼 @shangrenzhidao 访问请求大嘛,意思就是你网站 NB 了。

#3 楼 @small_fish__ 嗯,我知道,我的意思是它内部原理

#4 楼 @shangrenzhidao save 或 update 之前 select 一下,看有没有字段相同的记录。

唯一性验证是一个 SELECT, 插入数据是一个 INSERT。常见的写法是 validation 和 create/save 分开。这样,在多个线程请求的时候,可能会出现第一个请求的验证通过后,第二个请求接着写入造成重复数据。这种可能性存在,虽然很小,毕竟几乎同时请求并造成相同数据的概率太低了。

另一个写法是不做 Validation, 直接一个 loop 插入,直到没有重复的数据为止,并包裹在一个 transaction 里面。这样就肯定没问题的了。写入 token 常见这种做法。

#6 楼 @billy 谢谢,你的解释很到位 !

#6 楼 @billy 应用级别的唯一验证总是不牢靠的,如果要求非常严格就在数据库做唯一索引吧,这个有保证。

#6 楼 @billy 我说说我的理解,线程 A 请求验证通过,这时候线程 A 的数据还没有被插入数据库,而这时线程 B 也通过了验证,然后线程 A 插入完成,恰恰线程 B 也可以插入了。对不对?

#8 楼 @zgm 索引为什么可以保证唯一性?

A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. This constraint does not apply to NULL values except for the BDB storage engine. For other engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL. If you specify a prefix value for a column in a UNIQUE index, the column values must be unique within the prefix.

#9 楼 @shangrenzhidao

#6 楼 @billy 我说说我的理解,线程 A 请求验证通过,这时候线程 A 的数据还没有被插入数据库,而这时线程 B 也通过了验证,然后线程 A 插入完成,恰恰线程 B 也可以插入了。对不对?

你想的过于复杂了,数据库是有 Transaction 的,一个 Transaction 没有结束的话,Transaction 里面插入多少数据外面都看不到,所以要发生点问题是很容易的。Rails 的 Validator 只是为了返回更好看的错误,仅此而已,实际上啥都防不住的,还是要靠数据库自己保证自己的完整性。

#10 楼 @shangrenzhidao

#8 楼 @zgm 索引为什么可以保证唯一性?

层次不同,数据库设计的时候会考虑到这个问题,所以很容易解决。

13 楼 已删除

另外这帖子为什么要加精?

由于 validates_uniqueness_of(*attr_name) 是在 create 操作的时候调用的,所以当用户较多的时候(或者使用多个应用服务器的情况),可能会出现相同记录同时被 create,但是都还没有 save 的情况。因为此时对 rails 来说,数据库里还没有将要创建的记录。在用户提交,记录被保存至数据库的过程中,rails 不会再验证记录是否唯一,所以会造成数据库里有相同记录的情况。

@iBachue 数据库是不会给你写 transaction 的,什么时候需要 transaction, 都是靠 Rails 和你自己加的。

@rocLv create 和 save 在本质上是一回事。

@zgm 索引是索引,验证是验证,用的地方不一样。

#16 楼 @billy 不是 事实上总会有 Transaction 的 即使你不写 ActiveRecord 也会帮你加上

@iBachue ActiveRecord 不是数据库,是 Rails 的一部分。另外,AR 也只会自动加 callback 的部分,其余的逻辑要靠你自己写。

同问:这帖子为什么会加精,这是个新手问题啊。

这个不是 rails tutorial 第六章的唯一性验证的问题嘛,不过作者确实没有说清楚。只是说了如果不加数据库验证,任何 rails 程序都会有这样的问题:

21 楼 已删除

同问为何加精

手抖了?

#20 楼 @Cifer_Y 只是一笔带过而已,我 更关注的是细节问题

#12 楼 @iBachue “Rails 的 Validator 只是为了返回更好看的错误,仅此而已,实际上啥都防不住的,还是要靠数据库自己保证自己的完整性”这句话点开了我。谢谢

需要 登录 后方可回复, 如果你还没有账号请 注册新账号