Rails事务通过是否抛出异常来决定是否回滚操作,事务回滚后,同时将异常继续传递,我们通常要在begin resuce end中来捕获异常。
Rails还有一个ActiveRecord::Rollback异常,当使用raise ActiveRecord::Rollback, "..."后,只执行回滚操作,而不抛出异常。例如:
# 引发ActiveRecord::RollBack异常 def exception_t1 ActiveRecord::Base.transaction do card = Card.find(122348) card.coin = 55 card.save! raise ActiveRecord::Rollback, "故意抛出异常" end end def test_exception begin ActiveRecord::Base.transaction do exception_t1() puts "顺利执行" end rescue puts "发生异常" p $! end render :text => 123 end
上面第一个方法,是一个私有方法,它抛出ActiveRecord::Rollback,将会造成回滚,而不向外抛出异常,当外部也使用事务的话,将形成嵌套事务,嵌套事务会将父事务代码与子事务合并到一个事务中,所以这样就会造成一些很奇怪的结果,如果父事务代码不会造成回滚,那么子事务的代码也会正常执行,这违背了我们的本意。
我们可以在子事务中使用:requires_new => true,来规避它,这样,嵌套时,子事务可以按我们的意图进行回滚。