簡體   English   中英

Ruby on Rails的ActiveRecord與DBMS腳本

[英]Ruby on Rails's ActiveRecord vs DBMS scripts

我正在學習Ruby on Rails,並遵循一些指南來了解該框架。

目前,我正在閱讀有關ActiveRecord遷移的信息,在開發階段特別是當您使用敏捷並且經常更改需求時,最好跟蹤一下更改。

但是,我相信,如果您對數據庫進行了微調,最好使用特定於供應商的腳本(MySQL,Postgres等)。

不用說,我並不是要使這篇文章基於觀點,所以我的第一個問題是,您是否了解使用Rails構建應用程序的這種方法的優缺點( ActiveRecord遷移與DBMS特定腳本)。 我一直在互聯網上搜索,但沒有找到任何比較。

另外,我想知道是否存在任何風險,應該注意的事情,或者如果需要將這兩種方法結合使用,可以避免這樣做。

預先感謝您的評論/答案。 最好的祝福

TLDR:

您不想使用第三方工具來手動管理數據庫。 嘗試使您的數據庫代碼盡可能接近Rails的遷移。

故事

如果您正在執行CRUD應用程序,而在應用程序或數據庫端都不需要任何復雜的邏輯,那么Rails遷移就很棒。 此功能使您可以將增量更改寫入數據庫並回滾它們,而不會中斷生產中的應用程序。 假設您有一個“用戶”表,並想添加一個字段,我們稱之為“ second_email_address”。 您可以這樣做:

class AddSecondEmailAddressToUsers < ActiveRecord::Migration[5.2]

  def self.up
    add_column :users, :second_email_address, :string
  end

  def self.down
    remove_column :users, :second_email_address, :string
  end

end

Rails會根據遷移文件名跟蹤數據庫模式的“版本”,並能准確告訴您您的位置,並使您可以回滾任何您改變主意的事情。 您可以添加或刪除此列,而不會丟失表中的任何數據,除非存儲在該列中的數據除外。 這對於基本用例非常好。

當您想使數據庫更具個性時,事情會變得更加復雜。

以觸​​發器為例,假設您有一個表“ shops”,具有has_many:users,並且您希望在shops表的整數列中跟蹤用戶計數。 Rails關於配置的約定范式要求您在用戶模型中執行以下操作:

after_create :increase_shop_user_count
def increase_shop_user_count
  self.shop.user_count+=1
end

有了觸發器,您就可以...

create or replace trigger increase_shop_user_count
  after insert on users
  for each row
  begin
    update shops set user_count = user_count + 1 where shops.id = NEW.shop_id
  end;

使用觸發器的性能提升是驚人的。 但是,在大多數現實生活中,您都不關心此事,並且樂於權衡幾毫秒的延遲,以方便將其全部以Rails方式包含在Rails應用程序中。 但是,我保證當您有數千家商店,每個商店有數十萬用戶,並且應用程序中有許多其他類似甚至更復雜的功能時,您會改變主意。 沒錯,申請成功意味着您必須動手(並學會忽略別人的卑鄙評論,這些人會通知您您將在熔岩中煮沸直到永恆結束,因為他們不尊重“鐵路方式”,nts nts )。

在我的應用程序中,觸發器,過程,計划的事件中有大約2萬行SQL,這些行從Rails應用程序代碼庫中移出並移至數據庫層。 當然,它從多個方面(編寫SQL,遷移,測試...)都增加了一定程度的復雜性,但是到月底,公司每月要少支付2萬美元的EC2賬單。

例如,如果您想直接使用phpmyadmin進行此類操作,則必須手動執行每個操作,但是隨着應用程序復雜性的提高,您將不知所措,這轉化為支持午夜和停機時間的呼叫。 幸運的是,您仍然可以將Rails遷移與觸發器/存儲過程等配合使用。

您可以按照上面的示例在單獨的遷移文件中編寫SQL。 您可以使用例如hair_trigger之類的gem在模型內定義觸發器,並將其導出到schema.rb或structure.sql(盡管這並不涵蓋,並且過程/函數和事件似乎沒有等效項)。 您還可以將模式切換到SQL,並且所有代碼都會得到一個龐大的SQL文件,這太麻煩了。

但是,由於這不再是要定義表和列,而是更像是應用程序功能,因此您還可以在app /目錄中包含一個sql /目錄,並在其中對SQL代碼進行分組,例如:

# app/sql/mysql/triggers/increase_shop_user_count.sql
    create or replace trigger increase_shop_user_count
      after insert on users
      for each row
      begin
        update shops set user_count = user_count + 1 where shops.id = NEW.shop_id
      end;

然后在Rails遷移文件中執行以下操作:

class IncreaseShopUserCountTrigger < ActiveRecord::Migration[5.2]
  def self.up
    execute File.read( Rails.root.join("app","sql","mysql","triggers","increase_shop_user_count.sql"))
  end
  def self.down
    execute "drop trigger increase_shop_user_count"
  end
end

當然,當您有數百個這樣的嬰兒時,您希望有一個發現機制,這樣您就不必執行File.read ...每個觸發器/過程都像蠻子一樣。

底線:一點都不差! 因此,Rails遷移使您能夠對數據庫進行增量更改,並使它們保持井井有條,版本化且易於管理!

但是測試呢?

好吧,您會再一次脫離Rails約定的鋪砌好的道路。 您可以像這樣測試模型的行為:

it "changes shop user count after creation" do
  s = create :shop
  u = create :user, shop: s
  expect(s.reload.user_count).to eq 1 # because our database-side magic changed the count!
end

以后的編輯:上面的用戶計數器示例當然可以使用AR的計數器緩存功能進行重構,但希望可以證明這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM