rails事务2

Rails 的 transaction 事务处理

程序开发 2009年11月10日 07:56

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

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

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

要解决这个问题哪就要上 事务 了!

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

来看一下这一段例子:

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() 方法执行的语句,那么事务将不会起作用!

 

 

 

 

   
    这是一个老问题了, 也是做web开发必须要弄明白的, 其实是很简单的东西, 想想上学时被它搞得迷糊就觉得好笑!上班后做了开发, 渐渐明白, 共享一下, 希望对大家有所帮助!
   
    一 先说说http吧, 这个是web的根本大法

HTTP协议本身是无状态的,客户端只需要简单的向服务器请求,如:www.google.com/abc.html.服务器将文件内容返回给客户。无论是客户端还是服务器都没有必要纪录彼此过去的行为。然而人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,如www.google.com/search=美女。这种需求一方面迫使 HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求。 后来用户对WEB有了更高的要求, 如购物, 一个网络商店每天处理N个客户请求,当接到一个请求时,就需要知道这个客户在站点订了几个商品,有没有付款等。为此HTTP协议添加了cookie特性。cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。
   引用网上朋友的用例(忘记URL了,不好意思):
   让我们用几个例子来描述一下cookie和session机制之间的区别与联系。X曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
    由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie来达到保存标识的目的,但实际上它还有其他选择。注意session并不HTTP的内容,它是保存客户端状态的一种机制。
    
    二 理解cookie

    cookie简单来说就是服务器设置一些信息,将它存储在客户端, 就像上面的例子2。(客户端脚本如JavaScript或者VBScript也可以生成cookie,但是目的都是为了存储信息),当客户再次访问服务器时, 浏览器会带上cookies发送请求给服务器。浏览器处理cookies的是有规则的,只发送附和条件的cookies. 意思是,当访问麦当劳时,只需出示麦当劳的会员卡。
   
    三 理解session

    session其实更简单, 就像例子3,在客户端只有一个卡号,他每回来的时候,一出示卡号,服务器会查找当前卡号的信息,就知道他的状态了。它的实现可以用cookies,也可以用其它方法,如:作为查询字符串附加在URL后面。
    在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的 HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
    
     
posted @ 2009-08-21 12:04 坏份子 阅读(41) | 评论(0) |  编辑

2009年7月14日 #

源代码分析

首先看 transaction 方法

ActiveRecord::Transactions Public Class methods
     # File vendor
/ rails / activerecord / lib / active_record / transactions.rb, line  187
187 :     def transaction( & block)
188 :       self. class .transaction( & block)
189 :     end

 可以看出他是调用类方法,类方法代码如下:

       # File vendor / rails / activerecord / lib / active_record / transactions.rb, line  75
      def transaction(
& block)
        increment_open_transactions

        begin
          #connection 
is  kind of MysqlAdapter
          connection.transaction(Thread.current[
' start_db_transaction ' ],  & block)
        ensure
          decrement_open_transactions
        end
      end

#connection.transaction call method 
in
# File vendor
/ rails / activerecord / lib / active_record / connection_adapters / abstract / database_statements.rb, line  58
      # Wrap a block 
in  a transaction.  Returns result of block.
      def transaction(start_db_transaction 
=   true )
        transaction_open 
=   false
        begin
          
if  block_given ?
            
if  start_db_transaction
              begin_db_transaction
              transaction_open 
=   true
            end
            
yield
          end
        rescue Exception 
=>  database_transaction_rollback
          
if  transaction_open
            transaction_open 
=   false
            rollback_db_transaction
          end
          raise unless database_transaction_rollback.is_a
?  ActiveRecord::Rollback
        end
      ensure
        
if  transaction_open
          begin
            commit_db_transaction
          rescue Exception 
=>  database_transaction_rollback
            rollback_db_transaction
            raise
          end
        end
      end

 

 上面的代码即实现了rails中的transaction,可见ActiveRecord是不支持事务嵌套的。 如果模型使用的是相同的数据库, 那么用 ModelA.transaction 或 ModelB.transaction的作用是一样的。



      objecta.transaction do
        objectb.save
!
      end
  或者
      objectb.transaction 
do
        objecta.save
!
      end
  或者
      ModelA.transaction 
do
        objectb.save
!
      end

  都是一样的!

  这些对象的方面或类方面, 到最后都是转换成SQL,让数据库来执行, 如果明白这个,一切都变得简单了! 

就从SQL而言 "model.transaction do" 只是执行 Begin, "end" 执行Commit. 对于MYSQL个别是引挚支持的存储点功能不在本文讨论范围之内。补充一下, 目前只是SQLServer支持事务嵌套,所以如果说ROR支持事务嵌套也就有点勉强! 

 

  rails 多表事务 收藏

 

  1. def self.down  
  2.   ActiveRecord::Base.transaction do  
  3.     drop_table :users  
  4.     drop_table :roles_users  
  5.     drop_table :roles  
  6.     drop_table :static_permissions  
  7.     drop_table :roles_static_permissions  
  8.   end  
  9. end  
 

 

从上可以看到一种多个表同时操作的事情的方法

你可能感兴趣的:(Rails)