锁定老帖子 主题:在rails中优雅的进行模型校验
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-11-06
Quake Wang 写道 robbin 写道 我非常反对gigix这种不管三七二十一,任何请求进来都统统最后给commit一把的做法。因为很早以前我就做过性能测试,对于每个请求都commit的做法,虽然对请求处理的速度影响很小(大约5%的性能损失),但是对数据库会造成非常大的压力,会让数据库的CPU占用率直线上升。
gigix之前贴的代码里面是有判定非get request才进行transaction的open/commit,所以对数据库不会有影响的。 但有些GET也会有transaction的,比方说计算帖子点击啦什么的。GET请求另外写一套方案? |
|
返回顶楼 | |
发表时间:2008-11-06
robbin 写道 Quake Wang 写道 robbin 写道 我非常反对gigix这种不管三七二十一,任何请求进来都统统最后给commit一把的做法。因为很早以前我就做过性能测试,对于每个请求都commit的做法,虽然对请求处理的速度影响很小(大约5%的性能损失),但是对数据库会造成非常大的压力,会让数据库的CPU占用率直线上升。
gigix之前贴的代码里面是有判定非get request才进行transaction的open/commit,所以对数据库不会有影响的。 但有些GET也会有transaction的,比方说计算帖子点击啦什么的。GET请求另外写一套方案? 解决大部分情况,特殊情况特殊处理咯 那些地方难道不是本来也要写一个ActiveRecord::Base.transaction的吗? |
|
返回顶楼 | |
发表时间: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。而实际上根据我的实践经验,长事务很容易造成数据库资源的锁定,应该是被极力避免的。 |
|
返回顶楼 | |
发表时间:2008-11-06
robbin 写道 对于程序员来说,这意味着编码标准的混乱。比方说你自己写一个model的方法,你现在就会搞不清楚究竟要不要加transaction block。加吧,很可能该方法被POST action调用,没必要重复加了;不加吧,万一被GET action调用了,没有事务保护了。得,最后还是统统加上block保险。但是这样一来,你的filter不是白写了吗?还不如去掉得了,无谓拉长了transaction scope。而实际上根据我的实践经验,长事务很容易造成数据库资源的锁定,应该是被极力避免的。
从REST的角度来看,model本来就不应该知道自己的一个操作是否应该需要事务保护,因为只有在资源的角度上你才能判断一个操作是否需要事务保护。至于性能问题,我很少在它没有出现的时候去考虑它。性能瓶颈出现的时候再特殊处理它好了,为了一个想象中的性能瓶颈害得几百个action不得不多考虑一件事情,我不认为这是个划算的生意。 |
|
返回顶楼 | |
发表时间: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。 |
|
返回顶楼 | |
发表时间:2008-11-06
懒得引用了,因为这种事情从来就没有一概而论的最佳方案,你只是在精确的事务声明和节约开发成本之间权衡。如果你认为自己的场景有几百个通用情况和几个特殊情况,你可以考虑一种无伤大雅的通用方式让自己少考虑一个问题。如果你认为自己的场景全都是特殊情况,那么就去精确声明好了。
|
|
返回顶楼 | |
发表时间:2008-11-06
gigix大牛,我想问一下,数据库回滚后如何定位错误字段
还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗? |
|
返回顶楼 | |
发表时间:2008-11-06
blackwolf1983 写道 gigix大牛,我想问一下,数据库回滚后如何定位错误字段
还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗? 1. 回滚和定位错误字段是两个正交的需求 2. 验证工具和数据库事务是两个层面的正确性保证 |
|
返回顶楼 | |
发表时间:2008-11-06
gigix 写道 blackwolf1983 写道 gigix大牛,我想问一下,数据库回滚后如何定位错误字段
还有,你用java的那些框架,比如struts时,难道不用现成的验证工具吗?都是直接提交给数据库处理吗? 1. 回滚和定位错误字段是两个正交的需求 2. 验证工具和数据库事务是两个层面的正确性保证 您说话太专业了,我有些看不懂 1.正交的需求是不是说等数据库报错时再验证 2.两个保证,但我想不出来验证通过的数据为什么会在数据库端出错 |
|
返回顶楼 | |
发表时间:2008-11-07
最后修改:2008-11-07
我觉得LZ 的方法挺好的,按分层的思想就是 业务层的ruby 做校验,减轻数据库服务器负担嘛。业务层可以做负载均衡,而DB 只有一个。比用事务做检查就先进些。
但有些特殊情况,可能必须在事务的中间或者结尾才能检查,例如可能把发货数量按先进先出分配到批次之后,才能校验,这时候还是利用事务本身作检验比较好些。 |
|
返回顶楼 | |