数据库的结构也同源代码一样随着我们开发的进行而不断的发生着改变。在开发过程中,一般的我们需要像管理我们的源代码一样记录下数据库结构的整个变化过程,以便代码还原到指定版本后,数据库能同步的还原到指定的版本与源代码同步。为了方便这一操作,Yii给我们提供了Yiic migrate 这个命令,对应的也有一个 CDbMigration 类来描述各个版本之间的信息,从而实现通过命令来还原或者更新数据库到指定的版本。
cd protected
yiic migrate create tbl_user
F:\xampp\htdocs\swsg10\backend\protected>yiic help migrate
USAGE
yiic migrate [action] [parameter]
DESCRIPTION
This command provides support for database migrations. The optional
'action' parameter specifies which specific migration task to perform.
It can take these values: up, down, to, create, history, new, mark.
If the 'action' parameter is not given, it defaults to 'up'.
Each action takes different parameters. Their usage can be found in
the following examples.
EXAMPLES
* yiic migrate
Applies ALL new migrations. This is equivalent to 'yiic migrate up'.
* yiic migrate create create_user_table
Creates a new migration named 'create_user_table'.
* yiic migrate up 3
Applies the next 3 new migrations.
* yiic migrate down
Reverts the last applied migration.
* yiic migrate down 3
Reverts the last 3 applied migrations.
* yiic migrate to 101129_185401
Migrates up or down to version 101129_185401.
* yiic migrate mark 101129_185401
Modifies the migration history up or down to version 101129_185401.
No actual migration will be performed.
* yiic migrate history
Shows all previously applied migration information.
* yiic migrate history 10
Shows the last 10 applied migrations.
* yiic migrate new
Shows all new migrations.
* yiic migrate new 10
Shows the next 10 migrations that have not been applied.
F:\xampp\htdocs\swsg10\backend\protected>
1 生成数据库表: yiic migrate
2 降低N个版本: yiic migrate down n
3 升级N个版本: yiic migrate up n
4 升级到指定版本: yiic migrate to 101129_185401
5 重新执行步骤: yiic migrate redo [step]
6 显示迁移历史: yiic migrate history [limit]
7 显示未应用的迁移: yiic migrate new [limit]
这里有两点需要说明一下:
- 执行yiic命令是需要配置好相关的环境变量面的Yiic命令找不到Yii框架的代码。
- 命令中 tbl_user 是我们要做的更改的简要说明,这里我用的表明,当然也可以是其它的说明,一般只作为 migrate 生成类名的一部分,方便理解。帖一下执行过程吧
E:\WebRoot\TrackStar\protected>yiic migrate create tbl_user Yii Migration Tool v1.0 (based on Yii v1.1.9-dev) Create new migration 'E:\WebRoot\TrackStar\protected\migrations\m120406_063814_tbl_user.php'? [yes|no] yes
New migration created successfully. E:\WebRoot\TrackStar\protected>
执行完这个命令就会在 /protected/migrations 文件夹中生成要处理的PHP文件,如下图:
1 class m120406_063814_tbl_user extends CDbMigration{
2 public function up(){
3 // 新数据库版本的代码,可以是创建新表、修改表结构、增删数据 等等
4 // 具体可以参考 Yii文档的 CDbMigration 类说明。
5 $this->createTable('tbl_user', array(
6 'id' => 'pk',
7 'username' => 'VARCHAR(128) NOT NULL',
8 'password' => 'VARCHAR(128) NOT NULL',
9 'email' => 'VARCHAR(128) NOT NULL'
10 ));
11 }
12
13 public function down(){
14 // 这里是对应up写的还原部分。
15 // 如果up函数中写的是建表,这里可以删除表,如果up中写的是增加新元素,这里可以是删除。
// 如果是初始版本,不允许还原的话,将此函数返回一个false即可。
17 $this->dropTable('tbl_user');
18 }
19
20 /*
21 // 如果要迁移的数据牵扯多个表同步操作,可以通过下面两个方法来实现事务的迁移
22 public function safeUp(){
23 }
24
25 public function safeDown(){
26 }
27 */
28 }
以上代码我注释的很清楚了,我们的第一个版本就只是简单的创建了个tbl_user表,如果再还原到初始情况的话,就将这个表也drop掉。倘若你对于 createTable 之类的方法不了解,可以参考Yii文档的CDbMigration类说明,一般的百度一下就会有好多出来,如果实在找不到,我会在本文最后列出来。
在执行命令之前,我们需要修改下:/protected/config/console.php 中的配置,让命令能顺利的找到我们的数据库:
1 components'=>array(
2 ‘db'=>array(
3 'connectionString' => 'mysql:host=localhost;dbname=trackstar',
4 'emulatePrepare' => true,
5 'username' => 'root',
6 'password' => '',
7 'charset' => 'utf8',
8 ),
OK, 执行命令:
E:\WebRoot\TrackStar\protected>yiic migrate up Yii Migration Tool v1.0 (based on Yii v1.1.9-dev) Total 1 new migration to be applied:
m120406_063814_tbl_user Apply the above migration? [yes|no] yes
*** applying m120406_063814_tbl_user
> create table tbl_user ... done (time: 0.056s)
*** applied m120406_063814_tbl_user (time: 0.067s) Migrated up successfully. E:\WebRoot\TrackStar\protected>
OK, 看我们的数据库:
数据库表成功建立,其中, tbl_migration 表是用来管理每次数据库操作过程的,暂不细说。
再还原回去:
E:\WebRoot\TrackStar\protected>yiic migrate down Yii Migration Tool v1.0 (based on Yii v1.1.9-dev) Total 1 migration to be reverted:
m120406_063814_tbl_user Revert the above migration? [yes|no] yes
*** reverting m120406_063814_tbl_user
> drop table tbl_user ... done (time: 0.056s)
*** reverted m120406_063814_tbl_user (time: 0.069s) Migrated down successfully. E:\WebRoot\TrackStar\protected>
Ok,测试没问题了,我们再建一个新版本,用来想表中添加五条记录:
yiic migrate create tbl_user_adddata
生成的代码:
1 class m120406_072631_tbl_user_adddata extends CDbMigration
2 {
3 public function up(){
4 $this->insert('tbl_user', array('username' => 'test1', 'password' => 'pass1',
5 'email'=> 'test1@example.com'));
6 $this->insert('tbl_user', array('username' => 'test2', 'password' => 'pass2',
7 'email'=> 'test2@example.com'));
8 $this->insert('tbl_user', array('username' => 'test3', 'password' => 'pass3',
9 'email'=> 'test3@example.com'));
10 $this->insert('tbl_user', array('username' => 'test4', 'password' => 'pass4',
11 'email'=> 'test4@example.com'));
12 $this->insert('tbl_user', array('username' => 'test5', 'password' => 'pass5',
13 'email'=> 'test5@example.com'));
14
15 }
16
17 public function down(){
18 $this->delete('tbl_user', 'username = "test1"');
19 $this->delete('tbl_user', 'username = "test2"');
20 $this->delete('tbl_user', 'username = "test3"');
21 $this->delete('tbl_user', 'username = "test4"');
22 $this->delete('tbl_user', 'username = "test5"');
23 }
24
25 .....
这样就又加了个新版本,只要用命令:
yiic migrate up 1
这样就更新到新版本了, 使用
yiic migrate down 1
Customizing Migration Command 定制迁移命令
There are several ways to customize the migration command.
有几种方法来定制迁移命令。
Use Command Line Options 使用命令行选项
The migration command comes with four options that can be specified in command line:
在命令行中迁移命令可以使用如下四个选项
-
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.boolean,指定是否执行交互模式的迁移。默认为true,这意味着用户将被提示时执行特定迁移。您可以设置为false应该在做一个后台进程迁移
-
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 themigrations
sub-directory under the application base path.
string,指定存储所有迁移的类文件的目录。必须指定路径别名以及相应的目录必须存在。如果没有指定,它将使用应用程序的根路径下的themigrations子目录
migrationTable
: string, specifies the name of the database table for storing migration history information. It defaults totbl_migration
. The table structure isversion varchar(255) primary key, apply_time integer
.string,,指定存储迁移历史信息的数据库表的名称。默认tbl_migration。表的结构是版本VARCHAR(255)主键,apply_time整数。connectionID
: string, specifies the ID of the database application component. Defaults to 'db'.string,指定的数据库应用程序组件的ID。默认为'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.string,指定文件的路径,作为担任产生迁移类的代码模板。这必须指定一个路径别名(eg application.migrations.template)。如果没有设置,将使用一个内部模板。在该模板中,标记{ClassName}将被替换为实际的迁移类的名称。
To specify these options, execute the migrate command using the following format
实例如下
yiic migrate up --option1=value1 --option2=value2 ...
For example, if we want to migrate for a forum
module whose migration files are located within the module'smigrations
directory, we can use the following command:
例如,如果我们要迁移的一个论坛模块,其迁移位于模块的migrations目录内的文件,我们可以使用下面的命令:
yiic migrate up --migrationPath=ext.forum.migrations
Configure Command Globally配置全局命令
While command line options allow us to configure the migration command on-the-fly, sometimes we may want to configure the command once for all. For example, we may want to use a different table to store the migration history, or we may want to use a customized migration template. We can do so by modifying the console application's configuration file like the following,
虽然命令行选项允许我们配置迁移命令,有时我们可能需要一次配置所有的命令。例如,我们可能要使用不同的表来存储迁移历史,或者我们可能要使用一个定制的迁移模板。我们可以通过类似下面的控制台应用程序的配置文件修改,
return array(
......
'commandMap'=>array(
'migrate'=>array(
'class'=>'system.cli.commands.MigrateCommand',
'migrationPath'=>'application.migrations',
'migrationTable'=>'tbl_migration',
'connectionID'=>'db',
'templateFile'=>'application.migrations.template',
),
......
),
......
);
Now if we run the migrate
command, the above configurations will take effect without requiring us to enter the command line options every time.
现在,如果我们运行migrate命令,上述配置将一直有效,而无需每次配置。
事务迁移
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语句会引发冲突.