Rails rails 多表关联 save 的时候需不需要 transaction?

tumayun · 2012年03月24日 · 最后由 yangyanhao 回复于 2012年03月27日 · 7661 次阅读

如题 在新公司,还没弄清这边的习惯,结果写代码的时候悲剧了,都是根据以前的经验写的 在关联表操作的时候加上了 transaction,在 partial 里面用的是@var,结果 push 代码后,架构师说不要用 transaction,这样会锁行,然后影响性能,还有要把 partial 当成 function 来看,尽量不要里面使用类似@var的变量,而要用 local var,然后我就想问:

  1. 使用 transaction 的优点和缺点,以及各位平时都用不用(架构师说淘宝还有亚马逊等其他电商网站都不用 transaction)
  2. partial 里面用@var好还是 local var

thx!!!

2、partial 里当然用 local var 1、transaction 一般没显示的用过。我在自己写 cron 任务的时候用

不用事务通常是比较关注性能,对数据一致性或同步要求不高的情况

我相信支付宝到处都是 transaction..

1.如果关联表操作用的是 AR callback,那自动就加了 transaction 哦。如果自己写存储流程的话,建议还是加上比较好。淘宝可能有强大的异步机制吧,所以不用,这个我猜的。 2.partial 用 local var,不过有时一个 partial 在哪里使用到自己心里清楚的话,用@var也未尝不可嘛。

能不能深入的分析一下 transaction 的优劣?性能差在哪里?

经典例子就是银行取款,如果一边在提款机取钱,一边用存折在柜台取钱,如果两边同时取,一个账号只有 1000 元有可能被两边都取走,那怎么办呢?就给账号上个锁,一边操作的时候账户就锁住,另一边的操作只能排队,这就保证每次账户数据都是正确的。这就是事务,transaction,同步问题,资源锁的一个例子。有很多地方说事务就是里面的操作要不全改,要不全不改,这其实说的是事务的特点,也是一回事,全不改就是事务中如你银行操作其中一步错了,账户就会回滚,所有操作都不起效。如你所见,事务,上锁,是为了保证数据一致,上了锁,大家都得排队,性能就慢下来了

http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html 看了一下 api 确实需要加上好点 特别是 balance 这样的字段

@reducm 什么时候需要用到嵌套事务?与非嵌套事务有什么区别?

多表同时进行增删改操作我还没遇到过不用事务的情况

那你们架构师把 rails 的内建事务关掉了没?

1 只有在必要的时候才使用 Transaction,Transaction 的确不该滥用。 2 你说的@var是指成员变量吧,如果是的话, 那么,partial 里面用 local var 比@var好, 而且代码中应该尽量减少@var的数量, 等你当几年程序员之后,你会发现@var是和祸害, 绝大多数的 Bug 和奇怪的现象都和@var有关, 所以少用,但又不是说不能用,慢慢摸索吧。

还有,我记得,rails 在多表关联上,内部已经做了事务处理啦。 不需要程序员自己再调用事务处理啦, 你把代码写出来给大家看看吧。 看代码更加直观一些。

@hooopo @ery 其实是那种没有写 has_many 的广联,但是业务上确实是有关联的, 比如 deals 表与 n_deals 是一对一的关系,但是 rails 中没有声明,然后在 create action 里面代码 类似于: deals.save n_deals.save 并没有做其他处理,经常导致要是 n_deal 表单填错了的话,deal 保存上了,n_deal 却没保存上, 我觉得这样很不舒服,然后改成事务的了,然后就悲剧了

#13 楼 @tumayun 明白了,先说事务处理, 如果业务逻辑要求 deals.saven_deals.save 应该一起成功,或一起失败, 不能一个成功且另一个失败, 那么就要使用事务处理, 否则,没有必要使用事务处理。 至于业务逻辑,是产品经理或者项目经理决定的。

另外一个问题,我很奇怪,有这种关系,为什么不在 model 上做关联。 而且,在 action 中调用两次 save 是很不好的设计, 至少应该把两次 save 封装到一个 model 的 public 函数里。

#13 楼 @tumayun 我觉得看你这种说法,deals.save 和 n_deals.save,是需要 Transaction 的,不然你这段代码的结果是未知的,大多情况未知的状况不失很你可以再这段代码改成:

deals.save
raise "stupid error"
n_deals.save

然后看看数据库的结果给是否满足你们的需求,如果这样的数据无所谓依然可以继续的话,那就不用。但是这显然不是一个一刀切的问题,如果为性能不用 transaction,可是要设计一个回滚 deals 的办法,这种情况性能可能还不如 transaction。

即便是在 model 中的方法,以上的情况也是存在的。

  1. 就算你简单的 save 一下,Rails 也会把数据库操作放在 transaction 里,留意一下日志就知道了,所以,你无法避免。
  2. partial 里用 Instance Variable 主要是影响重用性。当不同的 view 里包含这个 partial 时,不同的 action 提供的数据未必放在同名的 Instance Variable 中。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号