數據庫之變遷

注意,數據遷移這玩意1.1.6以後纔可以用哦。另外,說一下,英文是migrate,翻譯爲遷移,但是我看大部分是數據庫的變更操作而已啊。

就跟源代碼一樣的,數據庫結構在我們開發維護數據庫驅動應用的同時,也在發展着。例如,在我們開發的時候,我們會想新創建一個數據庫的表,或者是在開發完成,項目上線後,才發現要給某個字段加一個索引。很重要的一點,必須記錄跟蹤這些數據庫結構方面的變化(遷移)。如果源代碼或者是數據庫不一致了,整個系統都很有可能被破壞了。出於這個原因,Yii提供了一個數據庫遷移工具,可以記錄數據庫的變化記錄,應用新的架構,或者是回滾到之前的架構。

以下步驟演示了我們在開發時如何使用數據遷移的工具:

1. 張三創建了一個新的變更(例如,創建了張表)

2. 張三把這個變更提交到了SVN。

3. 李四從SVN獲得更新後的結構。

4. 李四把這些更新應用到他自己本地的數據庫。

Yii通過調用yiic migrate的命令行工具來實現數據遷移的。這個工具支持新建數據庫遷移,應用,回滾,重做。可以查看遷移記錄,以及查看最新的鏡像。

接下來,我們將介紹怎麼使用這個工具。

注意:最好是用工程下的yiic,而不要用框架下的yiic命令。確保你的protected\migrations存在,並且目錄可寫。同時,還要檢查你的數據庫連接protected/config/console.php。

1.1 創建遷移

要創建一個新的變更,執行以下命令即可:

yiic migrate create <name>

name參數是制定一個很簡短的關於這個新遷移的描述,例如create_news_table。下面我們會看到,name就像是用一個PHP的類名。所以,只允許包含字母,數字或者是下劃線。

yiic migrate create create_news_table

上面的命令,會在protected/migrations目錄下,創建一個名爲m101129_185401_create_news_table.php的文件,裏面的初始代碼爲:

 
 
  1. class m101129_185401_create_news_table extends CDbMigration  
  2. {  
  3.     public function up()  
  4.     {  
  5.     }  
  6.     public function down()  
  7.     {  
  8.         echo "m101129_185401_create_news_table does not support migration down.nn";  
  9.         return false;  
  10.     }  
  11.     /*  
  12.     // implement safeUp/safeDown instead if transaction is needed  
  13.     public function safeUp()  
  14.     {  
  15.     }  
  16.     public function safeDown()  
  17.     {  
  18.     }  
  19.     */ 

注意到,上面類名跟文件是同名的,命名規則爲m<timestamp>_<name>。<timestamp>是UTC的時間戳(格式爲yymmdd_hhmmss)。

up()方法裏面包含了這次遷移所要做的實際動作;down()方法裏,包含了回滾需要做的操作。

有些時候,是沒有辦法做回滾的。例如,我們在up時刪除了一張數據表,我們在down的時候就沒有辦法恢復了。在這種情況下,遷移就被稱之爲不可逆的,意味着我們無法回滾到數據庫之前的那個狀態中。在上面的例子中,down()方法返回false,表示無法回滾。

INFO:從1.1.7版本開始,如果up或者down的方法返回false,所有的接下來的操作都會被取消。在1.1.6版本中,必須拋出異常,然後再取消接下來的遷移工作。

下面的例子,讓我們來看看新建一張表:

  1. class m101129_185401_create_news_table extends CDbMigration  
  2. {  
  3.     public function up()  
  4.     {  
  5.         $this->createTable('tbl news'array(  
  6.             'id' => 'pk',  
  7.             'title' => 'string NOT NULL',  
  8.             'content' => 'text',  
  9.         ));  
  10.     }  
  11.     public function down()  
  12.     {  
  13.         $this->dropTable('tbl news');  
  14.     }  

基類CDbMigration提供了一些方法,用來管理數據庫的數據以及結構。例如,CDbMigration::createTable用來創建新表,CDbMigration::insert用來插入記錄。這些方法都是用CDbMigration::getDbConnection()返回的句柄,默認是Yii::app()->db。

INFO:你會注意到,CDbMigration很像CDbCommand的命令。事實如此。

1.2 數據庫變遷事務

INFO:次功能是從yii的1.1.7 版本開始才支持

當執行復雜的數據庫變遷時,我們希望每個變動都是同時成功或者失敗,這樣可以保證數據庫的一致性。要做到這點,就用我們之前提到過的數據庫事務。

我們在開始的時候使用事務,然後在所有動作之後,結束事務:

  1. class m101129_185401_create_news_table extends CDbMigration  
  2. {  
  3.     public function up()  
  4.     {  
  5.         $transaction=$this->getDbConnection()->beginTransaction();  
  6.         try  
  7.         {  
  8.             $this->createTable('tbl news'array(  
  9.                 'id' => 'pk',  
  10.                 'title' => 'string NOT NULL',  
  11.                 'content' => 'text',  
  12.             ));  
  13.             $transaction->commit();  
  14.         }  
  15.         catch(Exception $e)  
  16.         {  
  17.             echo "Exception: ".$e->getMessage()."nn";  
  18.             $transaction->rollBack();  
  19.             return false;  
  20.         }  
  21.     }  
  22.     // ...similar code for down()  

或者是,採用更加簡便的方法,用safeUp(),safeDown() 替換up()以及down()兩個方法:

  1. class m101129_185401_create_news_table extends CDbMigration  
  2. {  
  3.     public function safeUp()  
  4.     {  
  5.         $this->createTable('tbl news'array(  
  6.             'id' => 'pk',  
  7.             'title' => 'string NOT NULL',  
  8.             'content' => 'text',  
  9.         ));  
  10.     }  
  11.     public function safeDown()  
  12.     {  
  13.         $this->dropTable('tbl news');  
  14.     }  

當Yii執行變遷時,會先開始一個數據庫事務,然後再調用safeUp()的方法(或者是safeDown())。如果在這兩個方法中有任何的錯誤,事務就會回滾,保證數據庫的完整性。

注意:並不是所有的數據庫系統都支持事務操作,另外,還有一些操作不能用在事務中。這種情況下,就要用up()跟down()了。在MYSQL當中,有些語句會被隱式提交的。

1.3 應用變遷

如果想應用所有的新變更,執行以下的語句:

yiic migrate

這個指令會列出所有新的變遷,如果你確定應用這些變遷,就會調用這些變遷類當中的up()方法,按照時間順序一個一個的執行。

當一個變遷應用以後,變遷工具就會在數據庫中的一個名爲tbl_migration表中,生成一條記錄。這條記錄用來幫助變遷工具辨別哪些變遷已經應用了,哪些還沒有。如果tbl_migration的表不存在,變遷工具會自動在數據庫創建一張。

有時候,我們只想更新一個或者是部分的變遷,我們可以用這個命令:

yiic migrate up 3

這個命令會應用3個新的變遷,當然我們可以更改3這個數字來決定應用幾個。

當然,我們也可以指定應用到哪個新變遷爲止:

yiic migrate to 101129_185401

上面方法中,我們用時間戳來指定我們想應用的變遷。如果從上次應用的變遷,到這個指定的變遷,中間還有許多沒應用的,所有這些都會被應用。如果這個指定的變遷是被應用過的,那麼這個之後的所有應用過的變遷都會被回滾。

1.4 回滾應用變遷

如果要回滾上一次或者是很多次之前的變遷,用以下的命令:

yiic migrate down [step]

step 代表想回滾應用的變遷數量,默認值是1, 也就是回滾到上一次的應用變遷前。

正如我們之前提到過的,並不是所有被應用過的變遷都可以回滾。如果嘗試回滾這樣的變遷,整個回滾都會終止。

1.5 重做變遷

重做,也就是之前應用過,回滾過,現在又要重新應用。可以按照以下的命令:

yiic migrate redo [step]

step的參數跟上面回滾是一樣的。

1.6 查詢變遷信息

除了應用,回滾數據庫變遷,這個變遷工具還可以用來查詢應用的變遷記錄信息。

yiic migrate history [limit]
yiic migrate new [limit]

參數limit指定了查詢的個數,如果沒指定該參數值,所有的變遷記錄都會被查詢出來。

第一個命令列出被應用過的變遷,第二個列出沒被應用過的。

1.7 修改變遷記錄

有時候,我們想修改這個變遷記錄的版本,但是又不真的去應用或者回滾該變遷。這經常發生於我們開發新的變遷時,我們可以用以下的命令來實現:

yiic migrate mark 101129_185401

這個指令跟yiic migrate非常相似,區別在於這個命令只是修改了數據庫中記錄的變遷記錄,實際上並沒有應用或者回滾該操作。

1.8 自定義變遷指令

有許多方式可以自定義變遷指令。

用命令行選項

命令行中,有4個選項可以用來自定義:

●interactive:boolean型。用來指定應用變遷時,是否採用互動模式。默認值是true,也就是在應用時,會提醒用戶。如果是false,那麼就是在後臺執行。

●migrationPath:string型。指定變遷類文件的存放路徑。這個路徑必須用別名的方式,而且必須存在。如果不存在,則會用工程下的migrations子目錄。

●migrationTable:string型。指定數據庫中的變遷記錄表。默認值是tbl_migration。表結構是version varchar(255) primary key, apply time integer。

●connectionID:string型。指定數據庫連接句柄,默認是db。

●templateFile:string型。指定生成變遷類時的代碼模板路徑。同樣的,需要路徑別名的格式。如果不存在,則內置的模板會被使用。

要指定這些選項,調用變遷指令時,用以下的格式:

yiic migrate up --option1=value1 --option2=value2 ...

例如,我們要從forum模塊下的變遷文件來應用,可以用下面的代碼:

yiic migrate up --migrationPath=ext.forum.migrations

設置全局命令

雖然命令行的選項讓我們可以在用的時候你可以有選擇,但是有時候我們想一次性就配置好。例如,我們想用另外的一張表來保存變遷記錄,或者我們想用一個自定義的變遷模板,我們可以在工程的控制面板進行工程:

  1. return array(  
  2.     ......  
  3.     'commandMap'=>array(  
  4.         'migrate'=>array(  
  5.             'class'=>'system.cli.commands.MigrateCommand',  
  6.             'migrationPath'=>'application.migrations',  
  7.             'migrationTable'=>'tbl migration',  
  8.             'connectionID'=>'db',  
  9.             'templateFile'=>'application.migrations.template',  
  10.         ),  
  11.     ......  
  12.     ),  
  13.     ......  
  14. ); 

這時候,當我們調用migrate的命令行時,上面的選項配置就會生效了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章