在我们开发程序的过程中,数据库的结构也是不断调整的。我们的开发中要保证代码和数据库库的同步。因为我们的应用离不开数据库。例如: 在开发过程中,我们经常需要增加一个新的表,或者我们后期投入运营的产品,可能需要为某一列添加索引。我们必须保持数据结构和代码的一致性。如果代码和数据库不同步,可能整个系统将无法正常运行。出于这个原因。yii提供了一个数据库迁移工具,可以保持代码和数据库是同步。方便数据库的回滚和更新。
下面的步骤说明了我们如何能够在开发过程中使用的数据库迁移:
Note: 使用yiic迁移命令,最好切换到指定的应用程序目录(e.g. cd path/to/protected)而不是在框架根目录。
要创建一个新的迁移(例如,创建一个新闻表),我们运行下面的命令:
yiic migrate create <name>
name参数是必须的跟指定的迁移做非常简短的描述(例如create_news_table)。正如我们的例子,由于name参数是用来作为一个PHP类名称的一部分。因此,它应该只包含字母,数字和/或下划线字符。
yiic migrate create create_news_table
上面的命令将在目录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() { } */ }
注意,创建迁移时类名作为文件名的格式是m<timestamp>_<name>,其中的<timestamp>是指UTC时间戳(yymmdd_hhmmss格式)和<name>通过命令参数指定。
up()方法应该包含实际的数据库迁移的实现代码,而down()方法是up()回滚代码。
有时, down()不指定具体代码。例如,如果我们在up()中删除表的行,我们将不能回滚up的操作。在这种情况下,迁移被称为不可逆的,这意味着我们不能回滚到以前的状态的数据库。在上述生成的代码,up()方法返回false表明,迁移无法恢复。
Info: 从版本1.1.7开始,如果 up() or down() 方法返回false,表示迁移被取消。此前1.1.6版本中,抛出异常取消迁移。
例子中介绍了一个创建新闻表的迁移。
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方法将打印方法所用的时间和打印有关该方法的参数的一些消息。
Info: 版本1.1.7后支持事务迁移功能。
执行复杂的数据库迁移的同时,我们通常要确保整个迁移成功或失败,从而使数据库保持一致性和完整性。为了实现这个目标,我们可以利用数据库的事务。
我们应该明确地指定启动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() }
获得事务支持一个更简单的方式是使用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()。如果任何DB错误safeUp()或safeDown()时,将回滚事务,从而确保数据库完整性。
Note: 不是所有的DBMS都支持事务。一些数据库查询不能放入事务。在这种情况下,您不得不使用up() 和down()。MySQL中,一些SQL语句可能会造成隐式提交。
应用所有可用的新的迁移(例如, 本地数据库最新),运行以下命令:
yiic migrate
该命令将显示所有新迁移的名单。如果确认应用迁移,它将运行那些up()方法执行迁移,执行顺序是按照类名的时间戳值的顺序。
在应用迁移是,迁移工具将保存记录到名为tbl_migration数据库表中。这使得该工具,可以确保那些迁移被应用。如果tbl_migration不存在,该工具会自动在DB应用程序指定的数据库中创建它
有时候,我们可能仅仅需要应用一个或几个新的迁移。我们可以用下面的命令:
yiic migrate up 3
此命令将应用3个新的迁移。通过修改值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]
其中,可选参数限制指定要显示的迁移。如果没有指定的限制,将显示所有可用的迁移。
第一条命令显示已应用的迁移,而第二个命令显示尚未应用的迁移。
有时候,我们可能要修改移民记录,这通常发生在没有实际应用或恢复有关迁移到一个特定的迁移版本或在开发一个新的迁移任务时。我们可以用下面的命令来实现。
yiic migrate mark 101129_185401
此命令和yiic迁移命令非常相似,除了它只能修改历史记录表,没有应用迁移或恢复迁移到指定的版本。
有几种方法来定制迁移命令。
在命令行中迁移命令可以使用如下四个选项:
interactive
: boolean,指定是否执行交互模式的迁移。默认为true,这意味着用户将被提示时执行特定迁移。您可以设置为false应该在做一个后台进程迁移
migrationPath
: string,指定存储所有迁移的类文件的目录。必须指定路径别名以及相应的目录必须存在。如果没有指定,它将使用应用程序的根路径下的themigrations子目录
migrationTable
: string,,指定存储迁移历史信息的数据库表的名称。默认tbl_migration。表的结构是版本VARCHAR(255)主键,apply_time整数。
connectionID
: string,指定的数据库应用程序组件的ID。默认为'DB'。
templateFile
: string,指定文件的路径,作为担任产生迁移类的代码模板。这必须指定一个路径别名(eg application.migrations.template)。如果没有设置,将使用一个内部模板。在该模板中,标记{ClassName}将被替换为实际的迁移类的名称。
实例如下
yiic migrate up --option1=value1 --option2=value2 ...
例如,如果我们要迁移的一个论坛模块,其迁移位于模块的migrations目录内的文件,我们可以使用下面的命令:
yiic migrate up --migrationPath=ext.forum.migrations
虽然命令行选项允许我们配置迁移命令,有时我们可能需要一次配置所有的命令。例如,我们可能要使用不同的表来存储迁移历史,或者我们可能要使用一个定制的迁移模板。我们可以通过类似下面的控制台应用程序的配置文件修改,
return array( ...... 'commandMap'=>array( 'migrate'=>array( 'class'=>'system.cli.commands.MigrateCommand', 'migrationPath'=>'application.migrations', 'migrationTable'=>'tbl_migration', 'connectionID'=>'db', 'templateFile'=>'application.migrations.template', ), ...... ), ...... );
现在,如果我们运行migrate命令,上述配置将一直有效,而无需每次配置。
数据库迁移 使用命令行..执行的是console/Application
所以要更改console/config下的配置...
'components.db'=>[
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=test',
'username' => 'root',
'password' => '******',
]
php yii migrate --migrationPath=@vendor/amnah/yii2-user/amnah/yii2/user/migrations