rails transaction 的用法

Rails 的 transaction 事务处理

最近太做一个数据排名统计,统计过程中需要删除旧的缓存统计数据,最开始写的时候就直接 CachePostTotal.connection.execute("truncate table cache_post_totals") 先把这个表给重置了,然后再循环往里面插入新的统计数据。

但后面发现,这样的做法存在大问题:

  • 当我 truncate table 的时候, cache_post_totals 表已经被清除了。但新的数据还没有存上去,如果在这个时候有人读取这张表时,就会找不到数据,这样是有问题的。
  • 在中间插入新数据的循环中有可能会出现异常、Model 验证不通过等情况而使得统计流程中断,但这个时候 cache_post_totals 表的数据已被改变。

要解决这个问题哪就要上 事务 了! Rails ActiveRecord 对事务的处理实现的很方便,只用Model.transaction do … end 将对 Model 表的操作的代码包起来就可以了,这样一来,在 transaction do .. end 之间的数据更新动作并不会立刻改变表里面的数据,而是要等到完全执行完成后,过了 end 才更新。

来看一下这一段例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
begin
  Post.transaction do
    # 删除旧数据
    Post.delete_all

    # 例子 新数据
    datas [{:title => "title1", :slug => "title-1"},{:title => "Title 2", :slug => "Title 2"}]
    counter = 0
    datas.each do |d|
      post = Post.new(d)
      if not post.save
        raise "*** #{post.errors.full_messages}"
      end
    end
  end
  puts "=== Done"
rescue Exception => ex
  puts "*** transaction abored!"
  puts "*** errors: #{ex.message}"
end

另外有个小细节需要注意,如果你是使用 Model.connection.execute() 方法执行的语句,那么事务将不会起作用!

交易Transactions

Transaction(交易)保證所有資料的操作都只有在成功的情況下才會寫入到資料庫,最著名的例子也就是銀行的帳戶交易,只有在帳戶提領金額及存入帳戶這兩個動作都成功的情況下才會將這筆操作寫入資料庫,否則在其中一個動作因為某些原因失敗的話就會放棄所有已做的操作將資料回復到交易前的狀態。在Rails中使用交易的方式像這樣:

ActiveRecord::Base.transaction do
  david.withdrawal(100)
  mary.deposit(100)
end

你可以在一個交易中包含不同Active Record的類別或物件,這是因為交易是以資料庫連線為範圍,而不是個別Model

User.transaction do
  User.create!(:name => ‘ihower‘)
  Feed.create!
end

注意到這裡我們要使用create!而不是create,這是因為前者驗證失敗才會丟出例外,好讓整個交易失敗。同理,在交易裡做更新應該使用update_attributes!而不是update_attributes

單一Modelsavedestroy方法已經幫你使用transaction包起來了,當資料驗證失敗或其中的回呼發生例外時,Rails就會觸發rollback。所以下述的交易區塊是多餘的不需要寫:

User.transaction do # 這是多餘的
  User.create!(:name => ‘ihower‘)
end

另外,由於資料的更新要在交易完成後才能被讀取到,所以如果你在after_save回呼裡讓外部服務存取(例如呼叫全文搜尋引擎做索引),很可能因為交易尚未完成,會讀取不到更新。這時候必須改用after_commit這個回呼,才能確保讀取到交易完成後的資料。

感谢http://ihower.tw/rails3/activerecord-others.html 和http://huacnlee.com/blog/rails-transaction-tutorial/作者分享知识

rails transaction 的用法

时间: 2024-10-16 03:19:59

rails transaction 的用法的相关文章

sql事务(Transaction)用法介绍及回滚实例_转

sql事务(Transaction)用法介绍及回滚实例 事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性 当对多个表进行更新的时候,某条执行失败.为了保持数据的完整性,需要使用事务回滚. 显示设置事务 代码如下 begin try   www.2cto.com begin transaction insert into shi

sql事务(Transaction)用法介绍及回滚实例

事务是将一系列操作作为一个单元执行,要么成功,要么失败,回滚到最初状态.在事务处理术语中,事务要么提交,要么中止.若要提交事务,所有参与者都必须保证对数据的任何更改是永久的.不论系统崩溃或是发生其他无法预料的事件,更改都必须是持久的.只要有一个参与者无法做出此保证,整个事务就会失败.事务范围内的所有数据更改将回滚到特定设置点. Begin TRANSACTION 语句1; If @@error<>0 Goto error 语句2; If @@error<>0 Goto error

Redis最有用的中文资源,你值得拥有

只是为了记录资源地址,最好直接访问doc.redisfans.com更美观 Redis 命令参考 本文档是 Redis Command Reference 和 Redis Documentation 的中文翻译版: 所有 Redis 命令文档均已翻译完毕, Redis 最重要的一部分主题(topic)文档, 比如事务.持久化.复制.Sentinel.集群等文章也已翻译完毕. 文档目前描述的内容以 Redis 2.8 版本为准, 查看更新日志(change log)可以了解本文档对 Redis 2

ROR路由分析

今天开始研究rails路由  基本用法 资源路由 resources :members 配置资源路由后,自动生成默认的7个动作 动作 地址 controller中方法 作用 index /members index 显示列表 show /members/:id show 显示详情 new /members/new new, 方法中要声明对象 进入新建表单页 create /members create 创建 edit /members/:id/edit edit, 方法中要查询对象 进入编辑表单

[面试] - Java方向问题1

1.     Forward与Redirect的区别,详细说明. 2.     Java里有哪些多线程的类 3.      抽象类和接口的区别?thedifferences between interface and abstract class? 4.     Servlet实例在一个应用中被创建了几次? 5.     说一说Servlet的生命周期? (Lifecycle) 6.     Servlet的作用域? 7.     SessionId. 的作用? 8.     Session的机

Redis 命令参考

本文档是 Redis Command Reference 和 Redis Documentation 的中文翻译版: 所有 Redis 命令文档均已翻译完毕, Redis 最重要的一部分主题(topic)文档, 比如事务.持久化.复制.Sentinel.集群等文章也已翻译完毕. 文档目前描述的内容以 Redis 2.8 版本为准, 查看更新日志(change log)可以了解本文档对 Redis 2.8 所做的更新. 你可以通过网址 doc.redisfans.com 在线阅览本文档, 也可以下

Mybatis:颠覆你心中对事务的理解

本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:https://mp.weixin.qq.com/s/osB-BOl6W-ZLTSttTkqMPQ 1.说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性.四大隔离级别.七大传播特性.四大还好说,问题是七大传播特性是哪儿来的?是Spring在当前线程内,处理多个数据库操作方法事务时所做的一

Mybatis:深入对事务的理解

1.说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性.四大隔离级别.七大传播特性.四大还好说,问题是七大传播特性是哪儿来的?是Spring在当前线程内,处理多个数据库操作方法事务时所做的一种事务应用策略.事务本身并不存在什么传播特性,不要混淆事务本身和Spring的事务应用策略.(当然,找工作面试时,还是可以巧妙的描述传播特性的) 2.一说到事务,人们可能又会想起create.begin.commit.rollback.close.suspend.可实际上,只有commit.rol

Hibernate核心类用法-使用Transaction管理事务

一个典型的事务应该使用下面的形式 在创建完Session对象后即使用beginTransaction()启动事务 从此开始直到commit()之间的代码 都会处于同一个事务中 这两个函数之间所有的数据库代码都会在commit()时一次性提交 在提交时 如果某一句代码执行出现异常 就会回滚这一次事物之间的所有执行代码 public User getUser(String username) throws HibernateException { Session session = null; Tr