天天看點

Rails migration簡介

migration好像是rails 1.0出的功能,到底它是什麼什麼東東?用來幹嗎的?且聽下面分解. <o:p></o:p>

migration是一種分布環境下的資料庫同步功能,它提供了: 1.獨立于特定SQL的schema描述(當然是用ruby DSL啦).目前除了DB2外别的主流商用和開源資料庫都被支援.(IBM真衰).顯然,這種資料庫獨立的schema描述不可能包括資料庫特定的細節, 是以在生産環境中需要再行調試優化. 2.schema和資料内容版本控制.我不是DBA啊(雖然曾經想過幹這個),不知道有什麼别的工具可以做資料庫版本控制. 3.基于版本控制的分布式資料庫同步. <o:p></o:p>

先來說說基于ruby DSL的schema描述巴,打打基礎. 如果rails項目中的資料庫已經設計配置好了,可以執行rake db:schema:dump(這是Rails1.1的rake新文法,以前是rake db_schema_dump) 然後會生成db/schema.rb檔案.打開一看,基本結構類似這樣的: <o:p></o:p>

<o:p> </o:p>

ActiveRecord::Schema.define(:version => 5) do<o:p></o:p>

  create_table "choices",:id => false, :force => true do |t|<o:p></o:p>

    t.column "name", :string,, :limit => 30, :default => 'idiolt'<o:p></o:p>

    t.column "content", :text, :limit => 100<o:p></o:p>

    t.column "question_id", :integer, :null => false<o:p></o:p>

  end<o:p></o:p>

...<o:p></o:p>

:version以後用了migrate才會看見,現在應該是空的,先不管這個. 如你所見這個表定義非常直覺.需要說明的幾個選項. <o:p></o:p>

:force代表強制覆寫,預設false後面執行db:schema:load把表結構導回資料庫的時候如果表已經存在由這個選項決定是否覆寫. :id參數預設為true,也就是按照rails約定每個表自動建立id字段作為主鍵.false的話意思是你自己在schema中建立主鍵. :limit和:default不用解釋了吧. :null也沒啥好解釋的,false代表着SQL裡的NOT NULL <o:p></o:p>

你們已經看到db:schema:load了,恭喜,現在哪怕你不關心版本控制和分布式同步這些 "遙遠的事". 你也可以從容在各種不同資料庫直接移植表結構了.這可是DBA都頭疼的事呢. 隻要改一下database.yml的配置再執行rake db:schema:load就可以了. <o:p></o:p>

現在來說說版本控制和同步.資料庫畢竟不是代碼,除了schema外還有資料的.像上面這樣 load導進去的話會覆寫掉所有的資料. 是以我們需要找一個對資料影響最小的方法來更新資料庫. 這部分需要做些手工操作了: script/generate migration XXX 建立一個migration版本,這個操作會在db/migration下産生nnn_XXX.rb檔案. 同時 generate model的時候也會順帶産生nnn_create_XXX.rb檔案. 内容類似: <o:p></o:p>

<o:p> </o:p>

class CreatePortfolios < ActiveRecord::Migration<o:p></o:p>

  def self.up<o:p></o:p>

    create_table :portfolios do |t|<o:p></o:p>

      t.column :name, :string<o:p></o:p>

    end<o:p></o:p>

  end<o:p></o:p>

  def self.down<o:p></o:p>

    drop_table :portfolios<o:p></o:p>

  end<o:p></o:p>

end<o:p></o:p>

up方法定義這個版本該做什麼,down定義怎麼復原版本. 這裡up裡面建立了一個表, 方法和上面schema.rb裡的一樣. 除此外更常用的是對字段和索引的修改方法, 如 add_column/rename_column/change_column等,詳見api文檔. 除了對表結構的修改,還可以做任何對資料的修改. 比如導入資料常用的先删掉index,然後再導入, 最後再重建index. <o:p></o:p>

定義好了migration後,我們可以執行rake db:migrate更新到最高的版本,或者指定復原到某個版本: rake db:migrate version=n. migration自動根據目前版本判定該從哪復原到哪. 在分布環境下,同步代碼後隻要執行一下就能保證資料庫狀态也是最新版本. <o:p></o:p>

engine/plugin也能使用migration,比如login engine,在不破壞使用者已有資料庫内容的條件下添加新的所需資料内容. <o:p></o:p>

另外需要注意的是每次使用migration後,db/schema.rb都會被重新整理,所有手工對這個檔案的修改都會丢失. <o:p></o:p>

migration預設是不支援外鍵的,原因是一部分資料庫如MySQL ISAM和SQLite不支援外鍵,同時外鍵也會給Rails的test fixture導入資料造成麻煩(這個好像有個很麻煩的解決辦法)。不過還是有個插件提供了外鍵的導出(rake db:schema:dump)和導入(rake db:schema:load)(可惜migration中無法正常使用)。 <o:p></o:p>

安裝: <o:p></o:p>

<o:p> </o:p>

script/plugin install svn://caboo.se/plugins/atmos/activerecord_foreign_key_extensions<o:p></o:p>

文法: <o:p></o:p>

<o:p> </o:p>

add_foreign_key_constraint table, foreign_key, reference_table, reference_column, :name => optional_constraint_name, :on_update => optional_on_update_action, :on_delete => optional_on_delete_action<o:p></o:p>