美文网首页程序员代码改变世界码农的世界
rails 使用after_commit 来替代 after_s

rails 使用after_commit 来替代 after_s

作者: AQ王浩 | 来源:发表于2014-09-18 22:46 被阅读1463次

    rails 使用after_commit 来替代 after_save

    首先得明白after_saveafter_commit的区别

    1、after_save 将回调函数包含在同一个事务中,那么要么全部成功,要么全部失败。回调函数中的抛出的异常会导致整个操作失败。

    2、after_commit 是在事务提交之后,再进行的处理,那么即使回调函数抛出异常,也不会导致之前的操作失败。

    举个例子。

    class ZZDeal
        attr_accessor :title
        after_save: record_to_redis
    
        def record_to_redis
            # TODO
            rails Exception
        end
    end
    
    # console
    zz = ZZDeal.last
    1] pry(main)> zz = ZZDeal.first
    D, [2014-09-18T19:38:13.416572 #10908] DEBUG -- :   ZZDeal Load (1.4ms)  SELECT  `zz_deals`.* FROM `zz_deals`   ORDER BY `zz_deals`.`id` ASC LIMIT 1
    => #<ZZDeal id: 1, title: 'my_first_name'>
    zz.title = "jjjj"
    zz.save
    
    D, [2014-09-18T19:38:22.943780 #10908] DEBUG -- :    (0.5ms)  BEGIN
    D, [2014-09-18T19:38:22.989825 #10908] DEBUG -- :   SQL (1.0ms)  UPDATE `zz_deals` SET `title` = 'jjjj', `updated_at` = '2014-09-18 19:38:22' WHERE `zz_deals`.`id` = 1
    D, [2014-09-18T19:38:22.990678 #10908] DEBUG -- :    (0.5ms)  ROLLBACK
    [5] pry(main)> zz.reload.title
    D, [2014-09-18T19:38:37.321616 #10908] DEBUG -- :   ZZDeal Load (1.6ms)  SELECT  `zz_deals`.* FROM `zz_deals`  WHERE `zz_deals`.`id` = 1 LIMIT 1
    => "my_first_name"
    
    发现,title并没有改变。  
    

    若我将 after_save 变更为 after_commit,便是另一种效果

    class ZZDeal
        attr_accessor :title
        after_commit: record_to_redis, :on => [:create, :update]
    
        def record_to_redis
            # TODO
            rails Exception
        end
    end
    
    zz = ZZDeal.last
    1] pry(main)> zz = ZZDeal.first
    D, [2014-09-18T19:38:13.416572 #10908] DEBUG -- :   ZZDeal Load (1.4ms)  SELECT  `zz_deals`.* FROM `zz_deals`   ORDER BY `zz_deals`.`id` ASC LIMIT 1
    => #<ZZDeal id: 1, title: 'my_first_name'>
    zz.title = "wahaha"
    
    [4] pry(main)> zz.save
    D, [2014-09-18T19:40:29.632423 #10926] DEBUG -- :    (0.7ms)  BEGIN
    D, [2014-09-18T19:40:29.687067 #10926] DEBUG -- :   SQL (0.8ms)  UPDATE `zz_deals` SET `title` = 'wahaha', `updated_at` = '2014-09-18 19:40:29' WHERE `zz_deals`.`id` = 1
    D, [2014-09-18T19:40:29.824718 #10926] DEBUG -- :    (0.6ms)  COMMIT
    D, [2014-09-18T19:40:29.825749 #10926] DEBUG -- :    (0.5ms)  ROLLBACK
    
    [6] pry(main)> zz.reload.title
    D, [2014-09-18T19:40:39.389478 #10926] DEBUG -- :   ZZDeal Load (8.4ms)  SELECT  `zz_deals`.* FROM `zz_deals`  WHERE `zz_deals`.`id` = 1 LIMIT 1
    => "wahaha"
    数据库先进行了COMMIT再进行了ROLLBACK,那么之前的数据肯定是保存成功了。
    

    所以两种情况分别对待,如果你确实是需要同时成功,同时失败,那么after_save 是不错的选择,但是,如果不希望回调函数影响数据的保存,那么你需要after_commit。
    另外,在after_save中,会出现脏数据的情况。

    宣传语

    历经两个半月的准备,三次大改版,十七次小改版。le1024终于要和大家见面了。

    le1024每天推荐1~3段,有趣、有爱、有故事的视频。

    为您工作、学习、生活之余增加一点快乐的感觉。程序员必看的快乐视频网站

    参考:
    yannini.me
    stackoverflow
    rails-bestpractices

    相关文章

      网友评论

        本文标题:rails 使用after_commit 来替代 after_s

        本文链接:https://www.haomeiwen.com/subject/ivkutttx.html