论坛首页 编程语言技术论坛

在rails中优雅的进行模型校验

浏览 19498 次
该帖已经被评为精华帖
作者 正文
   发表时间:2008-11-06  
Quake Wang 写道
robbin 写道
我非常反对gigix这种不管三七二十一,任何请求进来都统统最后给commit一把的做法。因为很早以前我就做过性能测试,对于每个请求都commit的做法,虽然对请求处理的速度影响很小(大约5%的性能损失),但是对数据库会造成非常大的压力,会让数据库的CPU占用率直线上升。

gigix之前贴的代码里面是有判定非get request才进行transaction的open/commit,所以对数据库不会有影响的。


但有些GET也会有transaction的,比方说计算帖子点击啦什么的。GET请求另外写一套方案?
0 请登录后投票
   发表时间:2008-11-06  
robbin 写道
Quake Wang 写道
robbin 写道
我非常反对gigix这种不管三七二十一,任何请求进来都统统最后给commit一把的做法。因为很早以前我就做过性能测试,对于每个请求都commit的做法,虽然对请求处理的速度影响很小(大约5%的性能损失),但是对数据库会造成非常大的压力,会让数据库的CPU占用率直线上升。

gigix之前贴的代码里面是有判定非get request才进行transaction的open/commit,所以对数据库不会有影响的。

但有些GET也会有transaction的,比方说计算帖子点击啦什么的。GET请求另外写一套方案?

解决大部分情况,特殊情况特殊处理咯
那些地方难道不是本来也要写一个ActiveRecord::Base.transaction的吗?
0 请登录后投票
   发表时间:2008-11-06  
gigix 写道
robbin 写道
Quake Wang 写道
robbin 写道
我非常反对gigix这种不管三七二十一,任何请求进来都统统最后给commit一把的做法。因为很早以前我就做过性能测试,对于每个请求都commit的做法,虽然对请求处理的速度影响很小(大约5%的性能损失),但是对数据库会造成非常大的压力,会让数据库的CPU占用率直线上升。

gigix之前贴的代码里面是有判定非get request才进行transaction的open/commit,所以对数据库不会有影响的。

但有些GET也会有transaction的,比方说计算帖子点击啦什么的。GET请求另外写一套方案?

解决大部分情况,特殊情况特殊处理咯
那些地方难道不是本来也要写一个ActiveRecord::Base.transaction的吗?


对于程序员来说,这意味着编码标准的混乱。比方说你自己写一个model的方法,你现在就会搞不清楚究竟要不要加transaction block。加吧,很可能该方法被POST action调用,没必要重复加了;不加吧,万一被GET action调用了,没有事务保护了。得,最后还是统统加上block保险。但是这样一来,你的filter不是白写了吗?还不如去掉得了,无谓拉长了transaction scope。而实际上根据我的实践经验,长事务很容易造成数据库资源的锁定,应该是被极力避免的。
0 请登录后投票
   发表时间:2008-11-06  
robbin 写道
对于程序员来说,这意味着编码标准的混乱。比方说你自己写一个model的方法,你现在就会搞不清楚究竟要不要加transaction block。加吧,很可能该方法被POST action调用,没必要重复加了;不加吧,万一被GET action调用了,没有事务保护了。得,最后还是统统加上block保险。但是这样一来,你的filter不是白写了吗?还不如去掉得了,无谓拉长了transaction scope。而实际上根据我的实践经验,长事务很容易造成数据库资源的锁定,应该是被极力避免的。

从REST的角度来看,model本来就不应该知道自己的一个操作是否应该需要事务保护,因为只有在资源的角度上你才能判断一个操作是否需要事务保护。至于性能问题,我很少在它没有出现的时候去考虑它。性能瓶颈出现的时候再特殊处理它好了,为了一个想象中的性能瓶颈害得几百个action不得不多考虑一件事情,我不认为这是个划算的生意。
0 请登录后投票
   发表时间:2008-11-06   最后修改:2008-11-06
gigix 写道
robbin 写道
对于程序员来说,这意味着编码标准的混乱。比方说你自己写一个model的方法,你现在就会搞不清楚究竟要不要加transaction block。加吧,很可能该方法被POST action调用,没必要重复加了;不加吧,万一被GET action调用了,没有事务保护了。得,最后还是统统加上block保险。但是这样一来,你的filter不是白写了吗?还不如去掉得了,无谓拉长了transaction scope。而实际上根据我的实践经验,长事务很容易造成数据库资源的锁定,应该是被极力避免的。

从REST的角度来看,model本来就不应该知道自己的一个操作是否应该需要事务保护,因为只有在资源的角度上你才能判断一个操作是否需要事务保护。至于性能问题,我很少在它没有出现的时候去考虑它。性能瓶颈出现的时候再特殊处理它好了,为了一个想象中的性能瓶颈害得几百个action不得不多考虑一件事情,我不认为这是个划算的生意。


第一、Rails框架的transaction block是定义在ActiveRecord::Base上,而不是ActionController上面,这已经是一个很明显的暗示了。

第二、我理解Rails的transaction block与其说是事务保护,不如说是“在代码里面进行显式的事务声明”,它声明了block内的代码需要事务范围。所以从这一点上来看,无论写model代码,lib代码还是action代码,只要程序员认为某段代码需要在一个事务范围内完成的时候,就应该加transaction block去显式的声明这一点。如果是我写代码,除非是单步事务,否则我会在model里面声明一次,然后在action里面调用model的时候再声明一次。而不应该因为有了一个统一的filter拦截web请求之后,放弃了在代码里面对事务的声明,这样的代码缺乏好的描述性。

第三、我们这里谈的事务毕竟是指数据库事务,而model需要不需要事务,是根据数据库操作来决定的,和REST无关,所以从REST的角度根本无从判断你需要不需要事务。就像我上面举的例子。从REST的角度来说访问本贴:GET /topics/238160,是不改变资源状态的,但是这里你不能得出不需要事务的结论。事实上因为我们需要记录用户访问轨迹,帖子点击次数,照样需要数据库事务。

第四、对于我们的应用场景来说我还是比较关注这个问题。因为数据库一旦出现IO瓶颈,是最棘手的问题,而commit操作会引起IO。
0 请登录后投票
   发表时间:2008-11-06  
懒得引用了,因为这种事情从来就没有一概而论的最佳方案,你只是在精确的事务声明和节约开发成本之间权衡。如果你认为自己的场景有几百个通用情况和几个特殊情况,你可以考虑一种无伤大雅的通用方式让自己少考虑一个问题。如果你认为自己的场景全都是特殊情况,那么就去精确声明好了。
0 请登录后投票
   发表时间:2008-11-06  
gigix大牛,我想问一下,数据库回滚后如何定位错误字段

还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗?

0 请登录后投票
   发表时间:2008-11-06  
blackwolf1983 写道
gigix大牛,我想问一下,数据库回滚后如何定位错误字段

还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗?


1. 回滚和定位错误字段是两个正交的需求
2. 验证工具和数据库事务是两个层面的正确性保证
0 请登录后投票
   发表时间:2008-11-06  
gigix 写道
blackwolf1983 写道
gigix大牛,我想问一下,数据库回滚后如何定位错误字段

还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗?


1. 回滚和定位错误字段是两个正交的需求
2. 验证工具和数据库事务是两个层面的正确性保证

您说话太专业了,我有些看不懂
1.正交的需求是不是说等数据库报错时再验证
2.两个保证,但我想不出来验证通过的数据为什么会在数据库端出错
0 请登录后投票
   发表时间:2008-11-07   最后修改:2008-11-07
我觉得LZ 的方法挺好的,按分层的思想就是 业务层的ruby 做校验,减轻数据库服务器负担嘛。业务层可以做负载均衡,而DB 只有一个。比用事务做检查就先进些。

但有些特殊情况,可能必须在事务的中间或者结尾才能检查,例如可能把发货数量按先进先出分配到批次之后,才能校验,这时候还是利用事务本身作检验比较好些。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics