原文:http://www.yiiframework.com/doc/guide/1.1/en/database.migration
译文如下,仅供参考:
Note: The database migration feature has been available since version 1.1.6.数据库迁移功能自从版本1.1.6已经可用。
Like source code, the structure of a database is evolving as we develop and maintain a database-driven application. For example, during development, we may want to add a new table; or after the application is put into production, we may realize the need of adding an index on a column. It is important to keep track of these structural database changes (called migration) like we do with our source code. If the source code and the database are out of sync, it is very likely the whole system may break. For this reason, Yii provides a database migration tool that can keep track of database migration history, apply new migrations, or revert existing ones.
The following steps how we can use database migration during development:
Yii supports database migration via the yiic migrate
command line tool. This tool supports creating new migrations, applying/reverting/redoing migrations, and showing migration history and new migrations.
In the following, we will describe how to use this tool.
在我们开发程序的过程中,数据库的结构也是不断调整的。我们的开发中要保证代码和数据库库的同步。因为我们的应用离不开数据库。例如: 在开发过程中,我们经常需要增加一个新的表,或者我们后期投入运营的产品,可能需要为某一列添加索引。我们必须保持数据结构和代码的一致性。如果代码和数据库不同步,可能整个系统将无法正常运行。出于这个原因。yii提供了一个数据库迁移工具,可以保持代码和数据库是同步。方便数据库的回滚和更新。
下面的步骤说明了我们如何能够在开发过程中使用的数据库迁移:
Note: It's better to use application-specific yiic (e.g.
cd path/to/protected
) when working withmigrate
command instead of one fromframework
directory.使用yiic迁移命令,最好切换到指定的应用程序目录(e.g. cd path/to/protected)而不是在框架根目录。
To create a new migration (e.g. create a news table), we run the following command:
要创建一个新的迁移(例如,创建一个新闻表),我们运行下面的命令:
yiic migrate create
The required name
parameter specifies a very brief description of the migration (e.g. create_news_table
). As we will show in the following, the name
parameter is used as part of a PHP class name. Therefore, it should only contain letters, digits and/or underscore characters.
name参数是必须的跟指定的迁移做非常简短的描述(例如create_news_table)。正如我们的例子,由于name参数是用来作为一个PHP类名称的一部分。因此,它应该只包含字母,数字和/或下划线字符。
yiic migrate create create_news_table
The above command will create under the protected/migrations
directory a new file namedm101129_185401_create_news_table.php
which contains the following initial code:
上面的命令将在目录protected/migrations下创建一个新的文件namedm101129_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() { } */ }
Notice that the class name is the same as the file name which is of the pattern m
, where
refers to the UTC timestamp (in the format of yymmdd_hhmmss
) when the migration is created, and
is taken from the command's name
parameter.
注意,创建迁移时类名作为文件名的格式是m
The up()
method should contain the code implementing the actual database migration, while the down()
method may contain the code reverting what is done in up()
.
up()方法应该包含实际的数据库迁移的实现代码,而down()方法是up()回滚代码
Sometimes, it is impossible to implement down()
. For example, if we delete table rows in up()
, we will not be able to recover them in down()
. In this case, the migration is called irreversible, meaning we cannot roll back to a previous state of the database. In the above generated code, the down()
method returns false
to indicate that the migration cannot be reverted.
有时, down()不指定具体代码。例如,如果我们在up()中删除表的行,我们将不能回滚up的操作。在这种情况下,迁移被称为不可逆的,这意味着我们不能回滚到以前的状态的数据库。在上述生成的代码,up()方法返回false表明,迁移无法恢复。
Info: Starting from version 1.1.7, if the
up()
ordown()
method returnsfalse
, all the following migrations will be canceled. Previously in version 1.1.6, one has to throw exceptions to cancel the following migrations.从版本1.1.7开始,如果 up() or down() 方法返回false,表示迁移被取消。此前1.1.6版本中,抛出异常取消迁移
As an example, let's show the migration about creating a news table.
例子中介绍了一个创建新闻表的迁移。
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'); } }
The base class CDbMigration provides a set of methods for manipulating data and schema of a database. For example, CDbMigration::createTable will create a database table, while CDbMigration::insert will insert a row of data. These methods all use the database connection returned by CDbMigration::getDbConnection(), which by default returns Yii::app()->db
.
基类CDbMigration提供了一套用于操纵数据和数据库的结构的方法。例如, CDbMigration::createTable将创建一个数据库表,而CDbMigration::insert将插入一行数据。这些方法都使用CDbMigration::getDbConnection()获取数据库连接,默认返回Yii::app()->db
Info: You may notice that the database methods provided by CDbMigration are very similar to those in CDbCommand. Indeed they are nearly the same except that CDbMigration methods will measure the time used by their methods and print some messages about the method parameters.您可能会注意到由CDbMigration数据库提供的方法和CDbCommand非常相似。事实上,他们几乎是相同的,除了CDbMigration方法将打印方法所用的时间和打印有关该方法的参数的一些消息
Info: The feature of transactional migrations has been supported since version 1.1.7.版本1.1.7后支持事务迁移功能。
While performing complex DB migrations, we usually want to make sure that each migration succeed or fail as a whole so that the database maintains the consistency and integrity. In order to achieve this goal, we can exploit DB transactions.
执行复杂的数据库迁移的同时,我们通常要确保整个迁移成功或失败,从而使数据库保持一致性和完整性。为了实现这个目标,我们可以利用数据库的事务。
We could explicitly start a DB transaction and enclose the rest of the DB-related code within the transaction, like the following:
我们应该明确地指定启动DB 事务和事务相关的数据的代码的操作,例如:
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() }
However, an easier way to get transaction support is to implement the safeUp()
method instead of up()
, andsafeDown()
instead of down()
. For example,
获得事务支持一个更简单的方式是使用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'); } }
When Yii performs the migration, it will start a DB transaction and then call safeUp()
or safeDown()
. If any DB error occurs in safeUp()
or safeDown()
, the transaction will be rolled back, thus ensuring the database remain in a good shape.
Yii的执行迁移时,它会启动一个数据库事务,然后调用safeUp()或safeDown()。如果任何DB错误safeUp()或safeDown()时,将回滚事务,从而确保数据库完整性
Note: Not all DBMS support transactions. And some DB queries cannot be put into a transaction. In this case, you will have to implement
up()
anddown()
, instead. And for MySQL, some SQL statements may cause implicit commit.不是所有的DBMS都支持事务。一些数据库查询不能放入事务。在这种情况下,您不得不使用up() 和down()。MySQL中,一些SQL语句可能会造成隐式提交。
To apply all available new migrations (i.e., make the local database up-to-date), run the following command:
应用所有可用的新的迁移(例如, 本地数据库最新),运行以下命令:
yiic migrate
The command will show the list of all new migrations. If you confirm to apply the migrations, it will run the up()
method in every new migration class, one after another, in the order of the timestamp value in the class name.
该命令将显示所有新迁移的名单。如果确认应用迁移,它将运行那些up()方法执行迁移,执行顺序是按照类名的时间戳值的顺序。
After applying a migration, the migration tool will keep a record in a database table named tbl_migration
. This allows the tool to identify which migrations have been applied and which are not. If the tbl_migration
table does not exist, the tool will automatically create it in the database specified by the db
application component.
在应用迁移是,迁移工具将保存记录到名为tbl_migration数据库表中。这使得该工具,可以确保那些迁移被应用。如果tbl_migration不存在,该工具会自动在DB应用程序指定的数据库中创建它
Sometimes, we may only want to apply one or a few new migrations. We can use the following command:
有时候,我们可能仅仅需要应用一个或几个新的迁移。我们可以用下面的命令:
yiic migrate up 3
This command will apply the 3 new migrations. Changing the value 3 will allow us to change the number of migrations to be applied.
此命令将应用3个新的迁移。通过修改值3,将允许我们改变应用的迁移的数目。
We can also migrate the database to a specific version with the following command:
我们也可以用下面的命令迁移到特定版本的数据库:
yiic migrate to 101129_185401
That is, we use the timestamp part of a migration name to specify the version that we want to migrate the database to. If there are multiple migrations between the last applied migration and the specified migration, all these migrations will be applied. If the specified migration has been applied before, then all migrations applied after it will be reverted (to be described in the next section).
也就是说,我们可以使用迁移名称+时间戳部分来指定我们要迁移的数据库的版本。如果有多个迁移例如最后一次应用的迁移和指定的迁移。所有这些迁移都会被应用。先应用最后一个迁移,然后再回滚指定的迁移(将在一节中所述)。
To revert the last one or several applied migrations, we can use the following command:
要恢复过去的一个或多个应用的迁移,我们可以使用下面的命令:
yiic migrate down [step]
where the optional step
parameter specifies how many migrations to be reverted back. It defaults to 1, meaning reverting back the last applied migration.
可选 step 参数指定恢复多少迁移。默认值为1,这意味着回滚最后一次迁移。
As we described before, not all migrations can be reverted. Trying to revert such migrations will throw an exception and stop the whole reverting process.
正如我们前面所述,并非所有的迁移都可以被回滚。试图回滚这样的迁移将抛出一个异常并停止整个恢复过程。
Redoing migrations means first reverting and then applying the specified migrations. This can be done with the following command:
重做迁移意味着首先恢复和再应用指定的迁移。这可以用下面的命令:
yiic migrate redo [step]
where the optional step
parameter specifies how many migrations to be redone. It defaults to 1, meaning redoing the last migration.
可选step参数指定重做多少迁移。默认值为1,这意味着重做最后的迁移。
Besides applying and reverting migrations, the migration tool can also display the migration history and the new migrations to be applied.
除了应用和恢复迁移,还可以显示迁移的历史和应用的新迁移。
yiic migrate history [limit] yiic migrate new [limit]
where the optional parameter limit
specifies the number of migrations to be displayed. If limit
is not specified, all available migrations will be displayed.
其中,可选参数限制指定要显示的迁移。如果没有指定的限制,将显示所有可用的迁移。
The first command shows the migrations that have been applied, while the second command shows the migrations that have not been applied.
第一条命令显示已应用的迁移,而第二个命令显示尚未应用的迁移。
Sometimes, we may want to modify the migration history to a specific migration version without actually applying or reverting the relevant migrations. This often happens when developing a new migration. We can use the following command to achieve this goal.
有时候,我们可能要修改移民记录,这通常发生在没有实际应用或恢复有关迁移到一个特定的迁移版本或在开发一个新的迁移任务时。我们可以用下面的命令来实现。
yiic migrate mark 101129_185401
This command is very similar to yiic migrate to
command, except that it only modifies the migration history table to the specified version without applying or reverting the migrations.
此命令和yiic迁移命令非常相似,除了它只能修改历史记录表,没有应用迁移或恢复迁移到指定的版本。
There are several ways to customize the migration command.
有几种方法来定制迁移命令。
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 to tbl_migration
. The table structure is version 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
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命令,上述配置将一直有效,而无需每次配置。