注意: yii從版本1.1.6以後才開始支援資料庫遷移特性。
和原始碼一樣,資料庫的結構也隨著我們開發和維護資料庫驅動應用程式而不斷壯大.例如,在開發期間,我們可能想要新增一個新的表; 或者在應用投入生產期以後,我們可能會意識到需要在某個列上添加索引. 追蹤這些資料庫結構的改變(被稱作遷移)和操作原始碼一樣很重要.如果原始碼和資料庫不同步了,可能這個系統都會中斷。正是因為這個原因,Yii框架提供了資料庫遷移工具,以便追蹤資料庫遷移歷史,應用新的遷移,或恢復舊的遷移.
下面的步驟顯示瞭如何在開發期間使用資料庫遷移:
Tim添加一個新的遷移(e.g. create a new table)
Tim提交一個新的遷移到版本控制工具(e.g. SVN, GIT)
Doug 從版本控制工具更新並取出一個新的遷移
Doug 應用新的遷移到本地開發版本的資料庫
Yii框架透過yiic migrate命令列工具支援資料庫遷移. 這個工具支援建立新的遷移,應用程式/復原/取消遷移,並且顯示遷移歷史和新的遷移。
接下來,我們將會描述如何使用這個工具。
注意: 當使用命令列遷移工具進行遷移時最好使用application目錄下的yiic (e.g. cd path/to/protected)而不是系統目錄下的. 確保擁有protectedmigrations 資料夾並且它是可寫的. 還若要檢查在protected/config/console.php中是否配置了資料庫連線。
想要創建一個新的遷移(例如創建一個news表), 我們可以運行如下命令:
yiic migrate create <name>
參數name是必須的,指定了關於這個遷移的非常簡短的描述(e.g. create_news_table). 正如我們在下面要展示的, name參數是PHP類別名稱的一部分。並且它只能包含字母,數字和下劃線。
yiic migrate create create_news_table
上面的命令將會在路徑protected/migrations下建立一個新的名為m101129_185401_create_news_table.php的文件,該文件包含了下列程式碼:
class m101129_185401_create_news_table extends CDbMigration { public function up(){} public function down() { echo "m101129_185401_create_news_table does not support migration down.\n"; return false; } /* // implement safeUp/safeDown instead if transaction is needed public function safeUp(){} public function safeDown(){} */ }
注意這個類別名稱和檔案名稱一樣,都是m
up() 方法應該包含實作資料庫遷移的程式碼, 而down() 方法包含的程式碼則用於還原up()方法中的操作。
有時候, 實作down()中的操作是不可能的。例如, 如果在up()方法中刪除表格的某一行, 就不能在down方法中恢復。 在這種情況下, 遷移被稱作不可逆的,這意味著我們不能回滾到資料庫的前一個狀態。 在上面產生的程式碼中, down() 方法傳回false來表示遷移的不可逆。
Info: 從版本1.1.7開始, 如果up() 或down() 方法回傳false, 下面的所有遷移都會被取消。而在版本1.1.6中, 必須拋出異常來取消下面的遷移。
讓我們用一個例子來展示建立一個news表的遷移.
class m101129_185401_create_news_table extends CDbMigration { public function up() { $this->createTable('tbl_news', array( 'id' => 'pk', 'title' => 'string NOT NULL', 'content' => 'text', )); } public function down() { $this->dropTable('tbl_news'); } }
基類CDbMigration 提供了一系列的方法來操作資料和資料庫,例如, CDbMigration::createTable 會創將資料庫表,CDbMigration::insert會插入一行資料。這些方法都使用CDbMigration::getDbConnection()傳回的資料庫連線, 預設是Yii::app()->db。
Info: 你可能注意到CDbMigration提供的資料庫方法和CDbCommand中的很類似。的確,它們基本上相同,除了CDbMigration方法會計算執行所耗的時間以及列印一些方法參數的資訊。
也可以擴展操作資料庫的方法,例如:
public function up() { $sql = "CREATE TABLE IF NOT EXISTS user( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL, password VARCHAR(32) NOT NULL, email VARCHAR(32) NOT NULL ) ENGINE=MyISAM"; $this->createTableBySql('user',$sql); } public function createTableBySql($table,$sql){ echo " > create table $table ..."; $time=microtime(true); $this->getDbConnection()->createCommand($sql)->execute(); echo " done (time: ".sprintf('%.3f', microtime(true)-$time)."s)\n"; }
Info: 事務遷移的特性從版本1.1.7起開始支援.
在複雜的資料庫遷移中, 我們經常想要確保每一個遷移都是成功的還是失敗的,以便資料庫保持一致性和完整性。 為了實現這個目標我們可以利用資料庫事務.
我們可以明確地開啟資料庫事務並附上其他資料庫相關的包含事務的程式碼,例如:
class m101129_185401_create_news_table extends CDbMigration { public function up() { $transaction=$this->getDbConnection()->beginTransaction(); try { $this->createTable('tbl_news', array( 'id' => 'pk', 'title' => 'string NOT NULL', 'content' => 'text', )); $transaction->commit(); }catch(Exception $e){ echo "Exception: ".$e->getMessage()."\n"; $transaction->rollback(); return false; } } // ...similar code for down() }
然而, 一個更簡單的獲取事務支援的方法是實作safeUp () 方法來取代up(), 以及safeDown() 來取代down(). 例如:
class m101129_185401_create_news_table extends CDbMigration { public function safeUp() { $this->createTable('tbl_news', array( 'id' => 'pk', 'title' => 'string NOT NULL', 'content' => 'text', )); } public function safeDown() { $this->dropTable('tbl_news'); } }
當Yii執行遷移的時候, 將會開啟資料庫遷移然後呼叫safeUp() 或safeDown(). 如果safeUp()和safeDown()出現任何錯誤, 事務將會回滾, 以確保資料庫保持一致性和完整性.
Note: 不是所有的DBMS都支援事務. 並且一些DB查詢不能放到事務中. 在這種情況下, 你比許實現up()和down()取而代之. 對MySQL而言, 一些SQL語句會引發衝突.
想要使用所有有效的新遷移(i.e., make the local database up-to-date), 執行下面的指令:
yiic migrate
这个命令会显示所有新迁移的列表. 如果你确定使用迁移, 它将会在每一个新的迁移类中运行up()方法, 一个接着一个, 按照类名中的时间戳的顺序.
在使用迁移之后, 迁移工具会在一个数据表tbl_migration中写一条记录——允许工具识别应用了哪一个迁移. 如果tbl_migration表不存在 ,工具会在配置文件中db指定的数据库中自动创建。
有时候, 我们可能指向应用一条或者几条迁移. 那么可以运行如下命令:
yiic migrate up 3
这个命令会运行3个新的迁移. 该表value的值3将允许我们改变将要被应用的迁移的数目。
我们还可以通过如下命令迁移数据库到一个指定的版本:
yiic migrate to 101129_185401
也就是我们使用数据库迁移名中的时间戳部分来指定我们想要迁移到的数据库的版本。如果在最后应用的数据库迁移和指定的迁移之间有多个迁移, 所有这些迁移都会被应用. 如果指定迁移已经使用过了, 所有之后应用的迁移都会恢复。
想要恢复最后一个或几个已应用的迁移,我们可以运行如下命令:
yiic migrate down [step]
其中选项 step 参数指定了要恢复的迁移的数目. 默认是1, 意味着恢复最后一个应用的迁移.
正如我们之前所描述的, 不是所有的迁移都能恢复. 尝试恢复这种迁移会抛出异常并停止整个恢复进程。
重做迁移意味着第一次恢复并且之后应用指定的迁移. 这个可以通过如下命令来实现:
yiic migrate redo [step]
其中可选的step参数指定了重做多少个迁移 . 默认是1, 意味着重做最后一个迁移.
除了应用和恢复迁移之外, 迁移工具还可以显示迁移历史和被应用的新迁移。
yiic migrate history [limit] yiic migrate new [limit]
其中可选的参数 limit 指定克显示的迁移的数目。如果limit没有被指定,所有的有效迁移都会被显示。
第一个命令显示已经被应用的迁移, 而第二个命令显示还没被应用的迁移。
有时候, 我们可能想要在没有应用和恢复相应迁移的时候编辑迁移历史来指定迁移版本. 这通常发生在开发一个新的迁移的时候. 我们使用下面的命令来实现这一目标.
yiic migrate mark 101129_185401
这个命令和yiic migrate to命令非常类似, 但它仅仅只是编辑迁移历史表到指定版本而没有应用或者恢复迁移。
有多种方式来自定义迁移命令。
使用命令行选项
迁移命令需要在命令行中指定四个选项:
interactive: boolean, specifies whether to perform migrations in an interactive mode. Defaults to true, meaning the user will be prompted when performing a specific migration. You may set this to false should the migrations be done in a background process. migrationPath: string, specifies the directory storing all migration class files. This must be specified in terms of a path alias, and the corresponding directory must exist. If not specified, it will use the migrations sub-directory under the application base path. migrationTable: string, specifies the name of the database table for storing migration history information. It defaults to tbl_migration. The table structure is version varchar(255) primary key, apply_time integer. connectionID: string, specifies the ID of the database application component. Defaults to 'db'. templateFile: string, specifies the path of the file to be served as the code template for generating the migration classes. This must be specified in terms of a path alias (e.g. application.migrations.template). If not set, an internal template will be used. Inside the template, the token {ClassName} will be replaced with the actual migration class name.
想要指定这些选项, 使用如下格式的迁移命令执行即可:
yiic migrate up --option1=value1 --option2=value2 ...
例如, 如果我们想要迁移一个论坛模块,它的迁移文件都放在模块的迁移文件夹中,可以使用如下命令:
yiic migrate up --migrationPath=ext.forum.migrations
注意在你设置布尔选项如interactive的时候,使用如下方式传入1或者0到命令行:
yiic migrate --interactive=0
配置全局命令
命令行选项允许我们快速配置迁移命令, 但有时候我们可能想要只配置一次命令. 例如, 我们可能想要使用不同的表来保存迁移历史, 或者我们想要使用自定义的迁移模板。我们可以通过编辑控制台应用的配置文件来实现,如下所示:
return array( ...... 'commandMap'=>array( 'migrate'=>array( 'class'=>'system.cli.commands.MigrateCommand', 'migrationPath'=>'application.migrations', 'migrationTable'=>'tbl_migration', 'connectionID'=>'db', 'templateFile'=>'application.migrations.template', ), ...... ), ...... );
现在如果我们运行迁移命令,上述配置将会生效,而不需要我们每一次在命令行中都输入那么多选项信息。
以上就是Yii框架官方指南系列增补版27——使用数据库:数据库迁移的内容,更多相关内容请关注PHP中文网(www.php.cn)!