开发时,我在laravel中遇到了很多迁移问题。
我创建了一个迁移。当我完成创建时,迁移中间(例如,外键约束)会出现一个小错误,使“php artisan migrate”失败。他确实告诉我错误的位置,然后迁移到一个不一致的状态,在错误发生之前对数据库进行了所有修改,而不是下一个修改。
这使得当我修复错误并重新运行migrate时,第一个语句失败,因为已经创建/修改了列/表。然后我知道的唯一解决方案是进入我的数据库并手动“回滚”所有内容,这样做的时间更长。
migrate:rollback尝试回滚以前的迁移,因为当前未成功应用当前迁移。
我还尝试将所有代码都包装到DB :: transaction()中,但它仍然不起作用。
这有什么解决方案吗?或者我只需要手动回滚东西?
编辑,添加一个例子(不编写Schema builder代码,只是某种伪代码):
Migration1:
Create Table users (id, name, last_name, email)
Migration1执行正常。几天后,我们进行了迁移2:
Create Table items (id, user_id references users.id)
Alter Table users make_some_error_here
现在将会发生的事情是,migrate将调用第一个语句,并使用外键为用户创建表项。然后,当他试图应用下一个语句时,它将失败。
如果我们修复了make_some_error_here,我们就无法运行migrate,因为它创建了表“items”。我们无法回滚(也不刷新,也不能重置),因为我们无法删除表用户,因为表项中存在外键约束。
然后,继续的唯一方法是转到数据库并手动删除表项,以便以一致的状态进行迁移。
答案 0 :(得分:12)
这不是Laravel限制,我打赌你使用MYSQL,对吗?
正如MYSQL文档所说here
某些语句无法回滚。通常,这些包括数据 定义语言(DDL)语句,例如那些创建或 drop database,创建,删除或更改表或存储的数据库 例程。
我们建议泰勒奥特威尔自己here说:
我最好的建议是每次迁移执行一次操作,以便您的 迁移过程非常精细。
答案 1 :(得分:4)
我使用的是MySql,我遇到了这个问题。
我的解决方案取决于您的down()
方法与up()
中的方法完全相同,但后退。
这就是我要去的地方:
try{
Schema::create('table1', function (Blueprint $table) {
//...
});
Schema::create('tabla2', function (Blueprint $table) {
//...
});
}catch(PDOException $ex){
$this->down();
throw $ex;
}
因此,如果某些内容失败,则自动调用down()
方法并再次抛出异常。
而不是在transaction()
之间使用迁移,而不是在此尝试之间执行
答案 2 :(得分:1)
只需从迁移文件中删除失败的代码,然后为失败的语句生成新的迁移。现在,当它再次失败时,数据库的创建仍然完好无损,因为它存在于另一个迁移文件中。
使用这种方法的另一个好处是,在还原数据库时,您可以获得更多控制和更小的步骤。
希望有所帮助:D
答案 3 :(得分:1)
我知道这是一个老话题,但是一个月前有活动,所以这是我的2美分。
此答案适用于MySql 8和Laravel 5.8 从MySql 8开始,MySql引入了原子DDL:https://dev.mysql.com/doc/refman/8.0/en/atomic-ddl.html Laravel在迁移开始时会检查模式语法是否支持事务中的迁移,以及是否确实启动了它。 问题在于MySql模式语法已将其设置为false。我们可以扩展Migrator,MySql模式语法和MigrationServiceProvider,然后像这样注册服务提供者:
<?php
namespace App\Console;
use Illuminate\Database\Migrations\Migrator as BaseMigrator;
use App\Database\Schema\Grammars\MySqlGrammar;
class Migrator extends BaseMigrator {
protected function getSchemaGrammar( $connection ) {
if ( get_class( $connection ) === 'Illuminate\Database\MySqlConnection' ) {
$connection->setSchemaGrammar( new MySqlGrammar );
}
if ( is_null( $grammar = $connection->getSchemaGrammar() ) ) {
$connection->useDefaultSchemaGrammar();
$grammar = $connection->getSchemaGrammar();
}
return $grammar;
}
}
<?php
namespace App\Database\Schema\Grammars;
use Illuminate\Database\Schema\Grammars\MySqlGrammar as BaseMySqlGrammar;
class MySqlGrammar extends BaseMySqlGrammar {
public function __construct() {
$this->transactions = config( "database.transactions", false );
}
}
<?php
namespace App\Providers;
use Illuminate\Database\MigrationServiceProvider as BaseMigrationServiceProvider;
use App\Console\Migrator;
class MigrationServiceProvider extends BaseMigrationServiceProvider {
/**
* Register the migrator service.
* @return void
*/
protected function registerMigrator() {
$this->app->singleton( 'migrator', function( $app ) {
return new Migrator( $app[ 'migration.repository' ], $app[ 'db' ], $app[ 'files' ] );
} );
$this->app->singleton(\Illuminate\Database\Migrations\Migrator::class, function ( $app ) {
return $app[ 'migrator' ];
} );
}
<?php
return [
'providers' => [
/*
* Laravel Framework Service Providers...
*/
App\Providers\MigrationServiceProvider::class,
],
];
当然,我们必须将事务添加到我们的数据库配置中... 免责声明-尚未测试,但仅查看代码即可按广告宣传的方式工作:)更新以进行测试...
答案 4 :(得分:0)
我认为最好的方法就像文档中所示:
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
请参阅:https://laravel.com/docs/5.8/database#database-transactions