John Little
John Little

Reputation: 12343

laravel migrations leave DB in an invalid state

If a migration fails half way through for any reason (E.g. typo), it commits half the migration, and leaves the rest out. It doesn't seem to try to roll back what it just did.(either by rolling back an encompassing transaction, or calling down())

If you try to manually rollback the last migration, e.g. php artisan migrate:rollback --step=1, it rolls back only the migration before last, i.e. the one before the one which failed.

Consider this migration:

public function up()
{
    DB::table('address')->insert(['id'=>1,'street'=>'Demo', 'country_id'=>83]);
    DB::table('customer')->insert(['id'=>1,'username'=>'demo','address_id'=>1]);
}

public function down()
{
    DB::table('customer')->where('id',1)->delete();
    DB::table('address')->where('id',1)->delete();
}

If the insert of the customer fails (e.g. we forgot to set a non null column, a typo, or a record exists when it should not), the address record WAS inserted.

migrate:rollback doesn't rollback this migration, it rolls back the one before, and we are left with a spurious orphaned address record. Obviously we can drop re-create the db and run the migration from scratch, but thats not the point - migrations should not leave half the migrations done and the DB in an invalid state.

Is there a solution? e.g. can one put transactions in the migration so it inserts all or nothing?

If we look in the migrations table after the half done migration has failed, it is not there.

NOTE: we use migrations to insert (and modify/delete) static data which the application requires to run. It is not dev data or test data. E.g. countries data, currencies data, as well as admin operators etc.

Upvotes: 1

Views: 954

Answers (1)

Raza Mehdi
Raza Mehdi

Reputation: 941

You should run these migrations inside a transaction:

DB::transaction(function () {
    // Your code goes here.
}

or you can use a try/catch block:

try {
    DB::beginTransaction();

     // Your code goes here ...

    DB::commit();
} catch(\Exception $e) {
    DB::rollBack();
}

Upvotes: 3

Related Questions