Rails validates_uniqueness_of 的必要性?

iwinux · 2012年08月03日 · 最后由 xds2000 回复于 2012年08月03日 · 7009 次阅读

根据 Rails 官方文档 所说,假如 table 中某个 field 建立了 unique key index,那么插入重复值(比如重复的 email)时就会抛 ActiveRecord::RecordNotUnique 异常。这个重复值的检查是在数据库级别进行的。

与此同时,大家平时用的比较多的方法是 validates_uniqueness_of,其实现方式是在 model validation 阶段以 find by field 查询数据库中是否存在重复值。由于 validation 和最终写入存在时间差,在高并发的情况下这种 validation 很不可靠。(所以无论如何都必须捕捉 ActiveRecord::RecordNotUnique 异常?)

我的问题:

  1. 既然 validates_uniqueness_of 不可靠,为什么不省掉这一步,直接捕捉(可能会抛出的)ActiveRecord::RecordNotUnique 异常?

  2. 在什么地方处理这个异常比较合适(controller 还是 model)?最好能统一处理所有 model 的 ActiveRecord::RecordNotUnique 异常。

我也觉得直接丢给数据库比较好,但问题很可能是数据库只会报个 IntegrityError,你不知道是哪 (几) 个 Field 重复导致的。我觉得即便如此也应该先 INSERT,失败再去查询。

MVC 中 Model 的作用是让开发者尽可能“忘记”DB 的存在吧 而且 validates_uniqueness_of 还有 :if, :scope 等选项,可以更灵活

对于问题 2,我也期待好答案

这里还有一个对 ActiveRecord::RecordNotUnique 的讨论 http://www.ruby-forum.com/topic/3908828

我也觉得没有用,每次都会生成这样一条 SQL:

SELECT 1 AS one FROM `users` WHERE `users`.`email` = xx LIMIT 1

不过,如果不加的话要自己对异常进行处理。

我的理解是,rails 作为一个一栈式框架,做了很多没用的事儿。这可以使应用不依赖其他组件(数据库/反向代理/缓存容器等)就可以正常工作。但实际上需要用户自己去取舍,比如 rails 可以处理静态文件,但是几乎所有实际环境都交给 nginx 处理。

有关第一个问题,首先可以想到的是 errors 的输出更加方便吧。 关于第二个问题有个额外的疑问,是如果问题 2 有一个好的解决方案,能否完善一下 ActiveRecord,由它负责捕获异常解决掉这个问题呢。

加个模型校验,做提交前的客户端校验比较方便。

我的观点是,数据库层面的唯一性一定要加。 model 层的唯一验证看是否需要错误回显等应用逻辑去决定。

#4 楼 @fleuria #5 楼 @Rei #6 楼 @hooopo

第一个问题按照大家的说法,应该是方便 form validation error messages 的显示。

第二个问题,也许在个别 controller 的 rescue_from 里面处理 ActiveRecord::RecordNotUnique 异常比较好?

#7 楼 @iwinux 是的。短时间内发生冲突,算是小概率事件了,给个统一错误就好。除非是商场抢拍这样的操作,就个别处理。

我的思路是,没遇到问题,就不要去考虑。有问题,先测试,找出 G 点。再技术讨论,设计设计软件架构。

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