Rails 中的事物处理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rails 中的事物处理相关的知识,希望对你有一定的参考价值。

1. 使用事物的原因

保证数据一致性, 当其中出现一个失败的时候,操作可以回滚

比如:

ActiveRecord::Base.transaction do 
    david.withdrawal(100) # withdrawal失败必须触发 exception
    mary.deposit(100) # deposit失败必须触发 exception
end

return false 不会出发操作回滚, 所以事物中要使用!的方法, 比如 save! update!

before_save 等callback也包含在事物中, 如果希望触发事物回滚, 需要能抛出异常

如果不希回滚则不抛出异常 或者放在事物之外 用after_commit等callbacl来处理

事务陷阱

不要在事务内部去捕捉 ActiveRecord::RecordInvalid 异常。因为某些数据库下,这个异常会导致事务失效,比如 Postgres。一旦事务失效,要想让代码正确工作,就必须从头重新执行事务。

另外,测试回滚或者事务回滚相关的回调时,最好关掉 transactional_fixtures 选项,一般的测试框架中,这个选项是打开的。

常见的事务反模式

  1. 单条记录操作时使用事务
  2. 不必要的使用嵌套式事务
  3. 事务中的代码不会导致回滚
  4. 在 controller 中使用事务

 

Exception handling and rolling back (待翻译)

Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you should be ready to catch those in your application code.

One exception is the ActiveRecord::Rollback exception, which will trigger a ROLLBACK when raised, but not be re-raised by the transaction block.

Warning: one should not catch ActiveRecord::StatementInvalid exceptions inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an error occurred at the database level, for example when a unique constraint is violated. On some database systems, such as PostgreSQL, database errors inside a transaction cause the entire transaction to become unusable until it‘s restarted from the beginning. Here is an example which demonstrates the problem:

# Suppose that we have a Number model with a unique column called ‘i‘.
Number.transaction do
  Number.create(i: 0)
  begin
    # This will raise a unique constraint error...
    Number.create(i: 0)
  rescue ActiveRecord::StatementInvalid
    # ...which we ignore.
  end

  # On PostgreSQL, the transaction is now unusable. The following
  # statement will cause a PostgreSQL error, even though the unique
  # constraint is no longer violated:
  Number.create(i: 1)
  # => "PGError: ERROR:  current transaction is aborted, commands
  #     ignored until end of transaction block"
end

以上是关于Rails 中的事物处理的主要内容,如果未能解决你的问题,请参考以下文章

获取Rails Activerecord以使用数据库的外部API ID

Rails:Rails 中的 POST 422(不可处理实体)?由于路线或控制器?

在 Rails 3 中处理 JS/ERB 模板中的 JSON

ruby on rails 4 - 捆绑安装grape-jbuilder

错误:Thor:Class 的未定义方法“deprecation_warning”

如何编辑旧的 Rails 迁移以添加参考?