0 0

关于Rails中多表保存的事务一致性5

关于Rails中多表操作的事务一致性

User has_one UserDetail 一个用户有一个用户明细,里面保存了用户的详细信息
User has_many MarkDetails 一个用户有多个积分明细,里面记录了每次获得积分的记录
Message 站内信

应用场景:
用户通过认证后,要更新一下users表中的是否通过验证的标志字段,同时更新一下用户明细表中的一些

信息,另外通过身份认证后,用户将得到100的积分,还要给用户发送一个站内认告诉他这件事情。

class User < ActiveRecord::Base

  def confirmed_width_auth(id_card)
    self.is_auth = 1
    self.user_detail.id_card = id_card

    mark_detail = self.mark_details.new
    mark_detail.mark = 100
    mark_detail.description = "身份认证得到积分"

    message = Message.new
    message.subject = "身份认证,得到积分"
    message.body = "你得到100积分"
    message.to_id = self.id

    # 很明显,上面涉及到要保存三张表的信息,我应该接下来怎么处理 来保证事务的一致性呢?
    self.save && mark_detail.save && message.save # 我这样做行不?
    # 另外好像在关联的表,在Rails中是可以进行事务处理的,而没有关联的表好像不能进行事务处理的,是这样的吗?
  
  end	

end


在那个<应用Rails进行敏捷开发>的书上有讲到Rails中active record中的事务处理,不过那例子讲到的是在同一个表中不同的记录间所执行的操作,对于多个不同的表(甚至是没有任何关联的表),我们应该怎么来安全的处理事务呢?

因为我做的是一个电子商务方面的应用,所以对于业务操作中的事务还是非常关注的,我希望能正确的安全的完成整个业务 方法的执行。

请有验证的和有想法的大大们指点一下,谢谢。
问题补充:
谢谢nt,
引用
1.捕捉异常。
2.数据库回滚,对象不回滚。(千万要记住)

关于1是应该在controller中进行么?
关于2你想说什么?能具体 一点吗?
问题补充:
transaction do
      self.save!
      mark_detail.save!
      message.save!
    end


我自己试了一下,以上的代码能正确工作,你为什么不用这样的代码呢?
比你刚才那圆环套圆环的方法好看一些啊。

我还是对 Rails的ar的事务处理机制不100%明白  
问题补充:
我自己测试过的,数据库中相关表中的记录的事务能保证的,你可以试试,

不过你所说的
非 User 对象应该无法回滚

是指user的实例 对象无法回滚到先前的状态吗?
2009年6月11日 11:13

5个答案 按时间排序 按投票排序

0 0

采纳的答案

这个 transaction do ... end 其实是调用了 Uer 的类方法。
而 User.transaction 只控制 user 表的回滚, 别的表它不管的。

这个三环可以简化一下(最后一环其实没用到):

User.transaction do
  MarkDetails.transaction do
    self.save!
    # 不过这一步可能连带保存了 mark_detail ?
    # 如果只生成一条 sql,就是单连接的事务,可以回滚 ……
    mark_detail.save!
    message.save!
  end
end 


你用
transaction do
  self.save!
  mark_detail.save!
  message.save!
  raise 'error'
end

试试看是不是都回滚了……

参考 http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

引用

A transaction acts on a single database connection. If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:


transaction 是连接相关的,如果能保证只在一个数据库连接中做所有事情,应该一个套就够了,但是不一定保险 ……

2009年6月11日 18:23
0 0

不对…… 你这个等于

User.transaction do
  ...
end

非 User 对象应该无法回滚

2009年6月11日 17:40
0 0

在 controller 和 model 都可以。如果不打算提供过于具体的出错信息,甚至可以写个处理异常的 filter,一次搞定。


第二条,考虑这个情况:
第一步保存了 user,第二步保存 mark_detail 出错,那么第一步保存的 user 记录会回滚消失。但这个回滚是数据库做的,回滚了什么东西 rails 不知道,所以 user 对象还是刚 save 时的状态,甚至还有一个子虚乌有的 id 属性…… 要继续使用这个对象,得注意这点。

2009年6月11日 17:11
0 0

更正: MarkDetails --> MarkDetail

还有一点设计上的: 这个东西涉及到多个类,万一 User 膨胀到很大很大(我说的是万一……),分离出 Service 类好点。

2009年6月11日 16:40
0 0

User.transaction do
  MarkDetails.transaction do
    Message.transaction do
      self.save!
      mark_detail.save!
      message.save!
    end
  end
end

save! 是异常版,如果其中出了异常,三张表都回滚。

另外要注意的:
1.捕捉异常。
2.数据库回滚,对象不回滚。(千万要记住)

2009年6月11日 16:37

相关推荐

Global site tag (gtag.js) - Google Analytics