2017-03-24 1 views
4

Laravel 5.3을 사용하고 있으며 프로덕션 서버를 이미 설정했습니다. 모든 DB 마이그레이션은 이미 다음과 같은 데이터베이스 설정을 사용하여 만든 :기존 데이터베이스의 Emoji Support에 대해 Laravel MYSQL을 utf8mb4로 변경

'mysql' => [ 
      'driver' => 'mysql', 
      'host' => env('DB_HOST', 'localhost'), 
      'port' => env('DB_PORT', '3306'), 
      'database' => env('DB_DATABASE', 'forge'), 
      'username' => env('DB_USERNAME', 'forge'), 
      'password' => env('DB_PASSWORD', ''), 
      'charset' => 'utf8', 
      'collation' => 'utf8_unicode_ci', 
      'prefix' => '', 
      'strict' => true, 
      'engine' => null, 
     ], 

하지만 지금은 내 사용자 중 일부는 그들에 이모티콘 아이콘이있는 양식을 저장하려고 할 때 오류가 발생하는 것으로보고했다. 검색 후 내가 대신이 같은 내 설정 있었어야 뭔가를 작동하려면에 대한 utf8mb4에 MySQL의 문자 집합을 설정해야한다는 것을 발견 :

'mysql' => [ 
      'driver' => 'mysql', 
      'host' => env('DB_HOST', 'localhost'), 
      'port' => env('DB_PORT', '3306'), 
      'database' => env('DB_DATABASE', 'forge'), 
      'username' => env('DB_USERNAME', 'forge'), 
      'password' => env('DB_PASSWORD', ''), 
      'charset' => 'utf8mb4', 
      'collation' => 'utf8mb4_unicode_ci', 
      'prefix' => '', 
      'strict' => true, 
      'engine' => null, 
     ], 

을이 프로덕션 서버에 있기 때문에, 나는 migrate:refresh 할 수 없습니다. 그래서 제 질문은 다음과 같습니다

내가 대신 utf8utf8mb4를 사용하고 같은에 laravel을 업데이트 laravel 마이그레이션을 사용하여 만든 기존 데이터베이스를 변경할 수있는 방법
  1. ? 이 작업을 수행하는 더 쉬운 방법이 있습니까?
  2. 위의 경우 가능하면 모든 테이블에 대해 utf8mb4 설정을 해제하거나 실제로 이모티콘을 사용하는 2 개의 테이블 열에만 사용하는 것이 좋습니다.

감사합니다.

답변

4
  1. 사용 원료 MySQL의 쿼리는 업데이트 테이블 이주 스크립트를 작성하고 php artisan migrate 명령

    use Illuminate\Database\Migrations\Migration; 
    
    class UpdateTableCharset extends Migration { 
    
        /** 
        * Run the migrations. 
        * 
        * @return void 
        */ 
        public function up() { 
          DB::unprepared('ALTER TABLE `table_name` CONVERT TO CHARACTER SET utf8mb4'); 
        } 
    
        /** 
        * Reverse the migrations. 
        * 
        * @return void 
        */ 
        public function down() { 
          DB::unprepared('ALTER TABLE `table_name` CONVERT TO CHARACTER SET utf8'); 
        } 
    } 
    
  2. 내 개인적인 취향, 업데이트 테이블을 실행합니다. 나는 그것이 더 나은

주의라고하는 증거가없는 : 당신은 여전히 ​​utf8mb4에 데이터베이스 설정을 유지해야합니다.

희망이 전체 데이터베이스에이를 기꺼이 누군가를 위해 당신에게

+0

감사합니다. @Saumini. 나는 그것을 지금 줄 것이다. – Neel

2

도움이 될 것입니다 나 자신이 이러한 스크립트를 필요로 발견

<?php 

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

class ChangeDbCharset extends Migration 
{ 

    /** 
    * Run the migrations. 
    * 
    * @return void 
    */ 
    public function up() 
    { 
     $charset = "utf8mb4"; 
     $collate = $charset."_unicode_ci"; 
     $dbName = Config::get('database.connections.'.Config::get('database.default').'.database'); 
     $query = "ALTER SCHEMA $dbName DEFAULT CHARACTER SET $charset DEFAULT COLLATE $collate;\n"; 
     DB::connection()->getPdo()->exec($query); 

     $dbName = Config::get('database.connections.'.Config::get('database.default').'.database'); 
     $result = DB::select(DB::raw('show tables')); 
     $test = DB::select(DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE = 'varchar' AND TABLE_SCHEMA = '$dbName';")); 
     //var_dump($test); 
     foreach($test as $t) 
     { 
      $query = "ALTER TABLE $t->TABLE_NAME CHANGE $t->COLUMN_NAME $t->COLUMN_NAME VARCHAR(191) CHARACTER SET $charset COLLATE $collate; \n"; 
      echo $query; 
      DB::connection()->getPdo()->exec($query); 
     } 
     $test = DB::select(DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE = 'text' AND TABLE_SCHEMA = '$dbName';")); 
     foreach($test as $t) 
     { 
      $query = "ALTER TABLE $t->TABLE_NAME CHANGE $t->COLUMN_NAME $t->COLUMN_NAME TEXT CHARACTER SET $charset COLLATE $collate; \n"; 
      echo $query; 
      DB::connection()->getPdo()->exec($query); 
     } 


     $result = DB::select(DB::raw('show tables')); 
     foreach($result as $r) 
     { 
      foreach($r as $k => $t) 
      { 
       $query = "ALTER TABLE `$t` CONVERT TO CHARACTER SET $charset COLLATE $collate; \n"; 
       echo $query; 
       DB::connection()->getPdo()->exec($query); 
      } 
     } 
     echo "DB CHARSET set to $charset , $collate"; 
    } 

    /** 
    * Reverse the migrations. 
    * 
    * @return void 
    */ 
    public function down() 
    { 
     $charset = "utf8"; 
     $collate = $charset."_unicode_ci"; 
     $dbName = Config::get('database.connections.'.Config::get('database.default').'.database'); 
     $query = "ALTER SCHEMA $dbName DEFAULT CHARACTER SET $charset DEFAULT COLLATE $collate;\n"; 
     DB::connection()->getPdo()->exec($query); 

     $dbName = Config::get('database.connections.'.Config::get('database.default').'.database'); 
     $result = DB::select(DB::raw('show tables')); 
     $test = DB::select(DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE = 'varchar' AND TABLE_SCHEMA = '$dbName';")); 
     //var_dump($test); 
     foreach($test as $t) 
     { 
      $query = "ALTER TABLE $t->TABLE_NAME CHANGE $t->COLUMN_NAME $t->COLUMN_NAME VARCHAR(255) CHARACTER SET $charset COLLATE $collate; \n"; 
      echo $query; 
      DB::connection()->getPdo()->exec($query); 
     } 
     $test = DB::select(DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE = 'text' AND TABLE_SCHEMA = '$dbName';")); 
     foreach($test as $t) 
     { 
      $query = "ALTER TABLE $t->TABLE_NAME CHANGE $t->COLUMN_NAME $t->COLUMN_NAME TEXT CHARACTER SET $charset COLLATE $collate; \n"; 
      echo $query; 
      DB::connection()->getPdo()->exec($query); 
     } 


     $result = DB::select(DB::raw('show tables')); 
     foreach($result as $r) 
     { 
      foreach($r as $k => $t) 
      { 
       $query = "ALTER TABLE `$t` CONVERT TO CHARACTER SET $charset COLLATE $collate; \n"; 
       echo $query; 
       DB::connection()->getPdo()->exec($query); 
      } 
     } 
     echo "DB CHARSET set to $charset , $collate"; 
    } 

} 
1

insomniak-DEV 대답 @에 기반을 만 축소됩니다 제한을 초과하고 인덱스에서 사용되는 경우 varchar입니다. 그렇지 않으면 변환되지만 크기는 그대로 유지됩니다. 열이 축소 될 경우 데이터가 잘 리는지 확인합니다.

또한 모든 텍스트 유형을 처리하고 각 테이블의 모든 변환을 속도를 높이기 위해 하나의 명령문으로 배치합니다.

Dryrun 플래그는 직접 적용하는 대신 사용할 수있는 sql을 출력합니다.

/** 
* Run the migrations. 
* 
* @return void 
*/ 
public function up() 
{ 
    $dryRun = true; 
    $this->convertDb('mysql', 'utf8mb4', 'utf8mb4_unicode_ci', $dryRun); 
    $this->convertDb('archive', 'utf8mb4', 'utf8mb4_unicode_ci', $dryRun); 
} 

/** 
* Reverse the migrations. 
* 
* @return void 
*/ 
public function down() 
{ 
    $dryRun = true; 
    $this->convertDb('archive', 'utf8', 'utf8_unicode_ci', $dryRun); 
    $this->convertDb('mysql', 'utf8', 'utf8_unicode_ci', $dryRun); 
} 

private function convertDb($connection, $charset, $collate, $dryRun) 
{ 
    $dbName = config("database.connections.{$connection}.database"); 

    $varchars = \DB::connection($connection) 
     ->select(\DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE = 'varchar' and (CHARACTER_SET_NAME != '{$charset}' or COLLATION_NAME != '{$collate}') AND TABLE_SCHEMA = '{$dbName}'")); 
    // Check if shrinking field size will truncate! 
    $skip = []; // List of table.column that will be handled manually 
    $indexed = []; 
    if ($charset == 'utf8mb4') { 
     $error = false; 
     foreach($varchars as $t) { 
      if ($t->CHARACTER_MAXIMUM_LENGTH > 191) { 
       $key = "{$t->TABLE_NAME}.{$t->COLUMN_NAME}"; 

       // Check if column is indexed 
       $index = \DB::connection($connection) 
        ->select(\DB::raw("SHOW INDEX FROM `{$t->TABLE_NAME}` where column_name = '{$t->COLUMN_NAME}'")); 
       $indexed[$key] = count($index) ? true : false; 

       if (count($index)) { 
        $result = \DB::connection($connection) 
         ->select(\DB::raw("select count(*) as `count` from `{$t->TABLE_NAME}` where length(`{$t->COLUMN_NAME}`) > 191")); 
        if ($result[0]->count > 0) { 
         echo "-- DATA TRUNCATION: {$t->TABLE_NAME}.{$t->COLUMN_NAME}({$t->CHARACTER_MAXIMUM_LENGTH}) => {$result[0]->count}" . PHP_EOL; 
         if (!in_array($key, $skip)) { 
          $error = true; 
         } 
        } 
       } 
      } 
     } 
     if ($error) { 
      throw new \Exception('Aborting due to data truncation'); 
     } 
    } 

    $query = "SET FOREIGN_KEY_CHECKS = 0"; 
    $this->dbExec($query, $dryRun, $connection); 

    $query = "ALTER SCHEMA {$dbName} DEFAULT CHARACTER SET {$charset} DEFAULT COLLATE {$collate}"; 
    $this->dbExec($query, $dryRun, $connection); 

    $tableChanges = []; 
    foreach($varchars as $t) { 
     $key = "{$t->TABLE_NAME}.{$t->COLUMN_NAME}"; 
     if (!in_array($key, $skip)) { 
      if ($charset == 'utf8mb4' && $t->CHARACTER_MAXIMUM_LENGTH > 191 && $indexed["{$t->TABLE_NAME}.{$t->COLUMN_NAME}"]) { 
       $tableChanges["{$t->TABLE_NAME}"][] = "CHANGE `{$t->COLUMN_NAME}` `{$t->COLUMN_NAME}` VARCHAR(191) CHARACTER SET {$charset} COLLATE {$collate}"; 
       echo "-- Shrinking: {$t->TABLE_NAME}.{$t->COLUMN_NAME}({$t->CHARACTER_MAXIMUM_LENGTH})" . PHP_EOL; 
      } else if ($charset == 'utf8' && $t->CHARACTER_MAXIMUM_LENGTH == 191) { 
       $tableChanges["{$t->TABLE_NAME}"][] = "CHANGE `{$t->COLUMN_NAME}` `{$t->COLUMN_NAME}` VARCHAR(255) CHARACTER SET {$charset} COLLATE {$collate}"; 
       echo "-- Expanding: {$t->TABLE_NAME}.{$t->COLUMN_NAME}({$t->CHARACTER_MAXIMUM_LENGTH})"; 
      } else { 
       $tableChanges["{$t->TABLE_NAME}"][] = "CHANGE `{$t->COLUMN_NAME}` `{$t->COLUMN_NAME}` VARCHAR({$t->CHARACTER_MAXIMUM_LENGTH}) CHARACTER SET {$charset} COLLATE {$collate}"; 
      } 
     } 
    } 

    $texts = \DB::connection($connection) 
     ->select(\DB::raw("select * from INFORMATION_SCHEMA.COLUMNS where DATA_TYPE like '%text%' and (CHARACTER_SET_NAME != '{$charset}' or COLLATION_NAME != '{$collate}') AND TABLE_SCHEMA = '{$dbName}'")); 
    foreach($texts as $t) { 
     $tableChanges["{$t->TABLE_NAME}"][] = "CHANGE `{$t->COLUMN_NAME}` `{$t->COLUMN_NAME}` {$t->DATA_TYPE} CHARACTER SET {$charset} COLLATE {$collate}"; 
    } 

    $tables = \DB::connection($connection) 
     ->select(\DB::raw("select * from INFORMATION_SCHEMA.TABLES where TABLE_COLLATION != '{$collate}' and TABLE_SCHEMA = '{$dbName}';")); 
    foreach($tables as $t) { 
     $tableChanges["{$t->TABLE_NAME}"][] = "CONVERT TO CHARACTER SET {$charset} COLLATE {$collate}"; 
     $tableChanges["{$t->TABLE_NAME}"][] = "DEFAULT CHARACTER SET={$charset} COLLATE={$collate}"; 
    } 

    foreach ($tableChanges as $table => $changes) { 
     $query = "ALTER TABLE `{$table}` ".implode(",\n", $changes); 
     $this->dbExec($query, $dryRun, $connection); 
    } 

    $query = "SET FOREIGN_KEY_CHECKS = 1"; 
    $this->dbExec($query, $dryRun, $connection); 

    echo "-- {$dbName} CONVERTED TO {$charset}-{$collate}" . PHP_EOL; 
} 

private function dbExec($query, $dryRun, $connection) 
{ 
    if ($dryRun) { 
     echo $query . ';' . PHP_EOL; 
    } else { 
     \DB::connection($connection)->getPdo()->exec($query); 
    } 
} 
관련 문제