Laravel Ошибка миграции при откате

Проверенные VDS на SSD в России: Датацентр №1 от 199руб

Тема в разделе "Laravel", создана пользователем mstdmstd, 17 янв 2018.

  1. mstdmstd

    mstdmstd Новичок

    Сообщения:
    397
    Ваш город:
    Ivano-Frankivs'k, Ukraine
    Address:
    Ivano-Frankivs'k, Ukraine
    Country:
    Location on Map:
    Всем привет,
    В Laravel5.5 делаю миграцию с 2мя полями и индексом:

    PHP:
    <?php

    use Illuminate\Support\Facades\Schema;
    use 
    Illuminate\Database\Schema\Blueprint;
    use 
    Illuminate\Database\Migrations\Migration;

    class 
    ModifyTaskAssignedToUsersIsLeaderStatus extends Migration
    {
        
    /**
         * Run the migrations.
         *
         * @return void
         */
        
    public function up()
        {
            try {
                
    DB::beginTransaction();

                
    Schema::table('task_assigned_to_users', function (Blueprint $table) {
                    
    $table->enum('status', ['A''C''N'])->comment(' A=>Accepted, C=>Canceled, N-New(Waiting for acception)')->after('user_id');
                    
    $table->boolean('is_leader')->default(false)->after('status');
                    
    $table->index(['task_id''status''is_leader'], 'task_assigned_to_users_task_id_status_is_leader_index');
                });

            } catch (
    Exception $e) {

                
    DB::rollBack();
                throw 
    $e;
            }
            
    DB::commit();
          
        }

        
    /**
         * Reverse the migrations.
         *
         * @return void
         */
        
    public function down()
        {
            try {
                
    DB::beginTransaction();

                
    Schema::table('task_assigned_to_users', function (Blueprint $table) {
                    
    $table->dropIndex('task_assigned_to_users_task_id_status_is_leader_index');
                    
    $table->dropColumn('status');
                    
    $table->dropColumn('is_leader');
                });

            } catch (
    Exception $e) {

                
    DB::rollBack();
                throw 
    $e;
            }
            
    DB::commit();

        }
    }
    Которая успешно создается, но при выполнении отката ошибка(в мигарциях я стараюсь выполнять и откат для тестирования):

    PHP:
    php artisan migrate:rollback

    In Connection
    .php line 664:
                                                                                                                                                                                                                                              
      
    SQLSTATE[HY000]: General error1553 Cannot drop index 'task_assigned_to_users_task_id_status_is_leader_index'needed in a foreign key constraint (SQLalter table `tsk_task_assigned_to_usersdrop index `task_assigned_to_users_task_id_status_is_leader_index`)                                                                                                                                                                                                             
                                                                                                                                                                                                                                              

    In PDOStatement.php line 107:                                                                                                                                                     
      
    SQLSTATE[HY000]: General error1553 Cannot drop index 'task_assigned_to_users_task_id_status_is_leader_index'needed in a foreign key constraint
                                                                                                                                                        

    In PDOStatement
    .php line 105:                                                                                                                                                     
      
    SQLSTATE[HY000]: General error1553 Cannot drop index 'task_assigned_to_users_task_id_status_is_leader_index'needed in a foreign key constraint 
    В откате индекс указан первым
    Поле task_id - это ссылка на tasks таблицу Не пойму почему ошибка и как это сиправить ?


    Спасибо !
     
  2. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.237
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    На всякий случай - https://dev.mysql.com/doc/refman/5.7/en/cannot-roll-back.html
    DDL запросы, которые обычно в миграциях, не откатываются во многих СУБД. Так что все эти транзакции, скорее всего, зря.
     
  3. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.787
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    @mstdmstd, https://laravel.com/docs/5.5/migrations#foreign-key-constraints см. dropForeign. Я, правда, не понял, откуда вообще FK взялся. Если ты ручками его сделал - не делай так, все должно быть в миграциях.

    А где еще, кроме mysql старше 8-й версии? (По сообщению об ошибке, конечно, понятно, что у него мыскль, и вряд ли это бета восьмерки, но все же).
     
    Последнее редактирование: 17 янв 2018
  4. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.237
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
  5. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.787
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Ух ты, и правда. Начиная с 5.3.

    В 5.0 не было такого, я с тех пор и не проверял.

    Это какой-то позор (с)
     
  6. mstdmstd

    mstdmstd Новичок

    Сообщения:
    397
    Ваш город:
    Ivano-Frankivs'k, Ukraine
    Address:
    Ivano-Frankivs'k, Ukraine
    Country:
    Location on Map:
    У меня mysql 5.7.20-0ubuntu0.17.10.1.
    Насчет транзакций, похоже да, не всегда срабатывают.
    Я нагуглил такой способ - но часто вижу что, если ошибка то транзакция есть в логе, но отката нет.

    И насчет логов : В моем app/Providers/AppServiceProvider.php я прописал трассировку запросов, включая транзакции:

    PHP:
    public function boot()
    {
    ...
    if (
    $this->app->environment('local')) {

    \
    Event::listen(
    [
    TransactionBeginning::class,
    ],
    ...
    \
    Event::listen(
    [
    TransactionCommitted::class,
    ],
    function (
    $event) {
    ...

    \
    DB::listen(function($query) {

    А нет возможности трассировать запросы миграции? Интересно было бы посмотреть ...
     
  7. MiksIr

    MiksIr miksir@home:~$

    Сообщения:
    3.136
    Ваш город:
    Третьяковская, Москва, город Москва, Россия
    Address:
    Moskva, Russia
    Country:
    Location on Map:
    А разве в мускуле 8 откатываются? Они там атомарны стали, это да, но откатываться вроде все еще не умеют.
     
  8. s4devel

    s4devel Новичок

    Сообщения:
    6
    Ваш город:
    Йошкар-Ола, Россия
    Address:
    Yoshkar-Ola, Russia
    Country:
    Location on Map:
    Всем привет!

    На сколько я понял, в предыдущих миграциях на поле task_assigned_to_users.task_id было наложено ограничение внешнего ключа. При этом в MySQL неявно (автоматически) создается индекс по данному полю, который является частью этого ограничения.

    В миграции вы создаете новый составной индекс task_assigned_to_users_task_id_status_is_leader_index в котором поле task_id указано первым. При этом MySQL заменит неявно созданный при создании ограничения внешнего ключа индекс по полю task_id на явно создаваемый task_assigned_to_users_task_id_status_is_leader_index и ограничение внешнего ключа будет использовать его.

    При откате миграции вы пытаетесь удалить индекс task_assigned_to_users_task_id_status_is_leader_index, который сейчас является частью ограничения внешнего ключа и получаете соответствующую ошибку.

    Для корректного отката миграции можно поступить так:
    1. Удаляем ограничение внешнего ключа.
    2. Удаляем индекс.
    3. Восстанавливаем ограничение внешнего ключа.
    т.о. полностью возвращаемся к состоянию до миграции.

    PHP:
    public function down()
    {
        
    Schema::table('task_assigned_to_users', function (Blueprint $table) {
            
    $table->dropForeign(['task_id']);
        });

        
    Schema::table('task_assigned_to_users', function (Blueprint $table) {
            
    $table->dropIndex('task_assigned_to_users_task_id_status_is_leader_index');
        });

        
    Schema::table('task_assigned_to_users', function (Blueprint $table) {
            
    $table->foreign('task_id')->references('id')->on('tasks');
        });
    }
     
    mstdmstd нравится это.