본문으로 건너뛰기
버전: 8.x

데이터베이스: 마이그레이션 (Database: Migrations)

소개

마이그레이션은 데이터베이스 버전 관리를 가능하게 해주는 도구로, 팀원들이 애플리케이션의 데이터베이스 스키마 정의를 직접 작성하고 공유할 수 있게 해줍니다. 만약 소스 코드를 동기화한 후 동료에게 직접 컬럼을 추가하라고 수동 지시한 적이 있다면, 바로 그 문제가 데이터베이스 마이그레이션으로 해결되는 문제입니다.

라라벨의 Schema 파사드는 라라벨이 지원하는 모든 데이터베이스 시스템에서 테이블을 생성하고 다룰 수 있도록 데이터베이스 친화적이지 않은(agnostic) 접근을 제공합니다. 일반적으로 마이그레이션은 이 파사드를 이용하여 데이터베이스의 테이블과 컬럼을 만들거나 수정합니다.

마이그레이션 생성

make:migration Artisan 명령어를 사용해 데이터베이스 마이그레이션 파일을 생성할 수 있습니다. 새로 생성된 마이그레이션 파일은 database/migrations 디렉터리에 저장됩니다. 각각의 마이그레이션 파일명에는 타임스탬프가 포함되어 있어, 라라벨이 마이그레이션 실행 순서를 정확히 파악할 수 있습니다.

php artisan make:migration create_flights_table

라라벨은 마이그레이션의 이름을 분석하여 테이블명과 새 테이블 생성 여부를 추측하려 시도합니다. 만약 라라벨이 이름에서 테이블명을 알아낼 수 있다면, 생성된 마이그레이션 파일에 해당 테이블명을 미리 입력해 둡니다. 반면, 테이블명을 자동으로 인식하지 못할 때는 마이그레이션 파일에서 직접 테이블명을 지정하면 됩니다.

생성된 마이그레이션의 경로를 원하는 곳으로 지정하고 싶다면, make:migration 명령어 실행 시 --path 옵션을 사용할 수 있습니다. 이 경로는 애플리케이션의 루트 디렉터리로부터 상대적으로 지정해야 합니다.

[!TIP] 마이그레이션의 스텁(stub, 템플릿). 파일은 스텁 퍼블리싱을 이용해 사용자 정의할 수 있습니다.

마이그레이션 스쿼싱

애플리케이션을 개발해가다 보면 점점 더 많은 마이그레이션 파일이 쌓이게 됩니다. 이로 인해 database/migrations 디렉터리가 수백 개의 마이그레이션 파일로 넘쳐날 수 있습니다. 이럴 때, 원한다면 여러 마이그레이션을 하나의 SQL 파일로 "스쿼싱(squash, 압축)"할 수 있습니다. 먼저, schema:dump 명령어를 실행해보세요.

php artisan schema:dump

// 현재 데이터베이스 스키마를 덤프하고, 기존 마이그레이션을 모두 정리(prune)합니다...
php artisan schema:dump --prune

이 명령어를 실행하면, 라라벨이 애플리케이션의 database/schema 디렉터리에 "스키마" 파일을 생성합니다. 이후 데이터베이스에 아직 어떤 마이그레이션도 실행된 이력이 없다면, 라라벨이 이 스키마 파일의 SQL 문을 먼저 실행합니다. 그리고 스키마 파일에 포함되지 않은 남은 마이그레이션들만 별도로 실행하게 됩니다.

이 스키마 파일을 소스 코드 관리에 꼭 커밋해두세요. 그러면 새로 합류한 다른 팀원도 애플리케이션의 초기 데이터베이스 구조를 빠르게 만들 수 있습니다.

[!NOTE] 마이그레이션 스쿼싱 기능은 MySQL, PostgreSQL, SQLite 데이터베이스에서만 제공되며, 데이터베이스의 커맨드라인 클라이언트를 활용합니다. 스키마 덤프는 메모리 기반 SQLite 데이터베이스에서는 복구가 지원되지 않습니다.

마이그레이션 구조

마이그레이션 클래스는 두 가지 메서드를 가집니다: updown. up 메서드는 데이터베이스에 새로운 테이블, 컬럼, 인덱스 등을 추가할 때 사용합니다. 그리고 down 메서드는 up 메서드에서 한 작업을 되돌릴 수 있게 정의해야 합니다.

이 두 메서드 모두 라라벨의 스키마 빌더를 사용하여 테이블을 명확하고 직관적으로 생성 및 수정할 수 있습니다. Schema 빌더에서 제공하는 모든 메소드에 대해 알고 싶으시다면, 관련 문서를 참고하세요. 아래 예시는 flights 테이블을 생성하는 마이그레이션의 예입니다.

<?php

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

class CreateFlightsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('flights');
}
}

익명 마이그레이션(Anonymous Migrations)

위의 예시에서 보았듯이, make:migration 명령어로 생성한 마이그레이션에는 라라벨이 클래스명을 자동으로 지정합니다. 하지만 필요에 따라 마이그레이션 파일에서 익명 클래스(anonymous class)를 반환하도록 선택할 수도 있습니다. 마이그레이션 파일이 매우 많아 클래스 이름이 겹칠 우려가 있을 때 특히 유용합니다.

<?php

use Illuminate\Database\Migrations\Migration;

return new class extends Migration
{
//
};

마이그레이션 연결 데이터베이스 지정

마이그레이션이 애플리케이션의 기본 데이터베이스 연결이 아닌 다른 연결에서 실행되어야 할 경우, 마이그레이션 클래스의 $connection 프로퍼티를 설정해야 합니다.

/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';

/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
}

마이그레이션 실행

모든 미실행 마이그레이션을 한 번에 실행하려면 migrate Artisan 명령어를 사용하세요.

php artisan migrate

지금까지 어떤 마이그레이션이 실행되었는지 확인하려면, migrate:status Artisan 명령어를 사용할 수 있습니다.

php artisan migrate:status

프로덕션 환경에서 강제로 마이그레이션 실행하기

일부 마이그레이션 작업은 파괴적이어서, 데이터 손실이 발생할 수도 있습니다. 이런 명령어를 프로덕션 데이터베이스에 실행하는 것을 방지하기 위해, 명령 실행 전 확인 메시지가 표시됩니다. 이 과정을 생략하고 강제로 실행하려면 --force 플래그를 사용하세요.

php artisan migrate --force

마이그레이션 롤백

가장 최근에 실행된 마이그레이션을 롤백하려면 rollback Artisan 명령어를 사용할 수 있습니다. 이 명령어는 "배치(batch)" 단위로 여러 개의 마이그레이션 파일을 한 번에 되돌립니다.

php artisan migrate:rollback

되돌리는 마이그레이션 개수를 제한하고 싶다면, rollback 명령어에 --step 옵션을 추가하세요. 예를 들어, 아래 명령어는 최근 5개의 마이그레이션만 롤백합니다.

php artisan migrate:rollback --step=5

migrate:reset 명령어를 사용하면 애플리케이션의 모든 마이그레이션이 롤백됩니다.

php artisan migrate:reset

한 번에 롤백 및 마이그레이션 실행

migrate:refresh 명령어를 사용하면, 모든 마이그레이션을 롤백한 뒤 다시 실행합니다. 이 명령어는 전체 데이터베이스를 효과적으로 재생성합니다.

php artisan migrate:refresh

// 데이터베이스를 리프레시하고 모든 시더를 실행합니다...
php artisan migrate:refresh --seed

refresh 명령어에도 --step 옵션을 사용해, 최근 N개의 마이그레이션만 롤백 및 재실행할 수 있습니다. 예를 들어, 최근 5개의 마이그레이션만 대상으로 하고 싶다면 아래와 같이 사용하세요.

php artisan migrate:refresh --step=5

모든 테이블 삭제 후 마이그레이션 실행

migrate:fresh 명령어는 데이터베이스의 모든 테이블을 삭제하고, 그 후에 다시 migrate 명령어를 실행합니다.

php artisan migrate:fresh

php artisan migrate:fresh --seed

[!NOTE] migrate:fresh 명령어는 프리픽스를 가진 테이블을 포함해 모든 데이터베이스 테이블을 삭제합니다. 다른 애플리케이션과 데이터베이스를 공유할 경우, 이 명령어는 신중하게 사용해야 합니다.

테이블

테이블 생성

새로운 데이터베이스 테이블을 생성하려면, Schema 파사드에서 create 메서드를 사용하세요. create 메서드는 두 개의 인수를 받는데, 첫 번째는 테이블 이름이고, 두 번째는 Blueprint 객체를 받아 테이블 구조를 정의하는 클로저입니다.

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

Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});

테이블을 생성할 때, 다양한 컬럼 메서드를 사용하여 컬럼을 정의할 수 있습니다.

테이블 / 컬럼 존재 여부 확인

hasTablehasColumn 메서드를 이용해 테이블 또는 컬럼이 존재하는지 확인할 수 있습니다.

if (Schema::hasTable('users')) {
// "users" 테이블이 존재합니다...
}

if (Schema::hasColumn('users', 'email')) {
// "users" 테이블과 "email" 컬럼이 모두 존재합니다...
}

데이터베이스 연결 및 테이블 옵션

기본 데이터베이스 연결이 아닌 다른 연결에서 스키마 작업을 하려면, connection 메서드를 사용하세요.

Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});

또한, 테이블 생성시 몇 가지 프로퍼티와 메서드로 추가적인 테이블 속성도 설정할 수 있습니다. MySQL에서 사용할 테이블의 스토리지 엔진을 지정하려면 engine 속성을 활용하세요.

Schema::create('users', function (Blueprint $table) {
$table->engine = 'InnoDB';

// ...
});

MySQL에서 생성할 테이블의 문자셋과 콜레이션을 지정하려면 charset, collation 속성을 사용할 수 있습니다.

Schema::create('users', function (Blueprint $table) {
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';

// ...
});

temporary 메서드를 이용하면 테이블을 "임시 테이블"로 만들 수 있습니다. 임시 테이블은 현재 연결된 데이터베이스 세션에서만 보이며, 연결이 종료되면 자동으로 삭제됩니다.

Schema::create('calculations', function (Blueprint $table) {
$table->temporary();

// ...
});

테이블 업데이트

기존 테이블을 수정하려면, Schema 파사드의 table 메서드를 사용할 수 있습니다. create와 마찬가지로, table 메서드는 테이블명과 Blueprint 인스턴스를 받는 클로저를 인수로 전달합니다. 이를 통해 컬럼이나 인덱스를 추가할 수 있습니다.

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

Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});

테이블 이름 변경 / 삭제

기존 데이터베이스 테이블의 이름을 변경하려면, rename 메서드를 사용하세요.

use Illuminate\Support\Facades\Schema;

Schema::rename($from, $to);

기존 테이블을 삭제하려면 drop 또는 dropIfExists 메서드를 사용할 수 있습니다.

Schema::drop('users');

Schema::dropIfExists('users');

외래 키가 있는 테이블 이름 변경

테이블의 이름을 변경하기 전에, 마이그레이션 파일에서 해당 테이블에 부여된 외래 키 제약 조건이 반드시 명시적으로 지정되어 있는지 확인해야 합니다. 이름을 자동 생성(convention)으로 사용하면, 외래 키 제약 조건 이름이 이전 테이블명을 참조하게 될 수 있습니다.

컬럼

컬럼 생성

기존 테이블에 컬럼을 추가하려면, Schema 파사드의 table 메서드를 사용할 수 있습니다. 이 메서드는 테이블명과 그리고 컬럼 추가를 정의하는 Illuminate\Database\Schema\Blueprint 인스턴스를 받는 클로저를 인수로 전달받습니다.

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

Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});

사용 가능한 컬럼 타입

스키마 빌더의 Blueprint는 데이터베이스 테이블에 추가할 수 있는 다양한 컬럼 타입에 대응하는 메서드를 제공합니다. 아래의 표에 각 컬럼 타입에 대해 사용할 수 있는 메서드를 정리해놓았습니다.

bigIncrements()

bigIncrements 메서드는 자동 증가하는 UNSIGNED BIGINT (기본키) 타입의 컬럼을 생성합니다.

$table->bigIncrements('id');

bigInteger()

bigInteger 메서드는 BIGINT 타입의 컬럼을 생성합니다.

$table->bigInteger('votes');

binary()

binary 메서드는 BLOB 타입의 컬럼을 생성합니다.

$table->binary('photo');

boolean()

boolean 메서드는 BOOLEAN 타입의 컬럼을 생성합니다.

$table->boolean('confirmed');

char()

char 메서드는 지정한 길이의 CHAR 타입 컬럼을 생성합니다.

$table->char('name', 100);

dateTimeTz()

dateTimeTz 메서드는 (옵션으로 정밀도 지정 가능) 시간대를 포함한 DATETIME 타입의 컬럼을 생성합니다.

$table->dateTimeTz('created_at', $precision = 0);

dateTime()

dateTime 메서드는 (옵션으로 정밀도 지정 가능) DATETIME 타입의 컬럼을 생성합니다.

$table->dateTime('created_at', $precision = 0);

date()

date 메서드는 DATE 타입의 컬럼을 생성합니다.

$table->date('created_at');

decimal()

decimal 메서드는 지정한 정밀도(전체 자릿수) 및 소수 자릿수(스케일)를 기준으로 한 DECIMAL 타입 컬럼을 생성합니다.

$table->decimal('amount', $precision = 8, $scale = 2);

double()

double 메서드는 지정한 정밀도(전체 자릿수) 및 소수 자릿수(스케일)를 기준으로 한 DOUBLE 타입 컬럼을 생성합니다.

$table->double('amount', 8, 2);

enum()

enum 메서드는 지정한 값 목록을 갖는 ENUM 타입 컬럼을 생성합니다.

$table->enum('difficulty', ['easy', 'hard']);

float()

float 메서드는 지정한 정밀도(전체 자릿수) 및 소수 자릿수(스케일)를 기준으로 한 FLOAT 타입 컬럼을 생성합니다.

$table->float('amount', 8, 2);

foreignId()

foreignId 메서드는 UNSIGNED BIGINT 타입의 컬럼을 생성합니다.

$table->foreignId('user_id');

foreignIdFor()

foreignIdFor 메서드는 지정된 모델 클래스에 대한 {컬럼}_id UNSIGNED BIGINT 타입의 컬럼을 추가합니다.

$table->foreignIdFor(User::class);

foreignUuid()

foreignUuid 메서드는 UUID와 동등한 컬럼을 생성합니다.

$table->foreignUuid('user_id');

geometryCollection()

geometryCollection 메서드는 GEOMETRYCOLLECTION과 동등한 컬럼을 생성합니다.

$table->geometryCollection('positions');

geometry()

geometry 메서드는 GEOMETRY와 동등한 컬럼을 생성합니다.

$table->geometry('positions');

id()

id 메서드는 bigIncrements 메서드의 별칭입니다. 기본적으로는 id 컬럼을 생성하지만, 다른 이름을 부여하고 싶다면 컬럼명을 인수로 전달할 수 있습니다.

$table->id();

increments()

increments 메서드는 자동 증가하는 UNSIGNED INTEGER와 동등한 컬럼을 기본 키로 생성합니다.

$table->increments('id');

integer()

integer 메서드는 INTEGER와 동등한 컬럼을 생성합니다.

$table->integer('votes');

ipAddress()

ipAddress 메서드는 VARCHAR와 동등한 컬럼을 생성합니다.

$table->ipAddress('visitor');

json()

json 메서드는 JSON과 동등한 컬럼을 생성합니다.

$table->json('options');

jsonb()

jsonb 메서드는 JSONB와 동등한 컬럼을 생성합니다.

$table->jsonb('options');

lineString()

lineString 메서드는 LINESTRING과 동등한 컬럼을 생성합니다.

$table->lineString('positions');

longText()

longText 메서드는 LONGTEXT와 동등한 컬럼을 생성합니다.

$table->longText('description');

macAddress()

macAddress 메서드는 MAC 주소를 저장하기 위한 컬럼을 생성합니다. PostgreSQL과 같은 일부 데이터베이스는 이 용도의 전용 컬럼 타입을 제공하며, 그 외의 데이터베이스 시스템은 문자열 타입 컬럼을 사용하게 됩니다.

$table->macAddress('device');

mediumIncrements()

mediumIncrements 메서드는 자동 증가하는 UNSIGNED MEDIUMINT와 동등한 컬럼을 기본 키로 생성합니다.

$table->mediumIncrements('id');

mediumInteger()

mediumInteger 메서드는 MEDIUMINT와 동등한 컬럼을 생성합니다.

$table->mediumInteger('votes');

mediumText()

mediumText 메서드는 MEDIUMTEXT와 동등한 컬럼을 생성합니다.

$table->mediumText('description');

morphs()

morphs 메서드는 {column}_id UNSIGNED BIGINT와 동등한 컬럼, 그리고 {column}_type VARCHAR와 동등한 컬럼을 추가하는 편의 메서드입니다.

이 메서드는 다형적 Eloquent 연관관계에 필요한 컬럼을 정의할 때 사용합니다. 아래 예제에서는 taggable_idtaggable_type 컬럼이 생성됩니다.

$table->morphs('taggable');

multiLineString()

multiLineString 메서드는 MULTILINESTRING과 동등한 컬럼을 생성합니다.

$table->multiLineString('positions');

multiPoint()

multiPoint 메서드는 MULTIPOINT와 동등한 컬럼을 생성합니다.

$table->multiPoint('positions');

multiPolygon()

multiPolygon 메서드는 MULTIPOLYGON과 동등한 컬럼을 생성합니다.

$table->multiPolygon('positions');

nullableTimestamps()

nullableTimestamps 메서드는 timestamps 메서드의 별칭입니다.

$table->nullableTimestamps(0);

nullableMorphs()

이 메서드는 morphs 메서드와 유사하지만, 생성되는 컬럼들이 "nullable"로 설정됩니다.

$table->nullableMorphs('taggable');

nullableUuidMorphs()

이 메서드는 uuidMorphs 메서드와 유사하지만, 생성되는 컬럼들이 "nullable"로 설정됩니다.

$table->nullableUuidMorphs('taggable');

point()

point 메서드는 POINT와 동등한 컬럼을 생성합니다.

$table->point('position');

polygon()

polygon 메서드는 POLYGON과 동등한 컬럼을 생성합니다.

$table->polygon('position');

rememberToken()

rememberToken 메서드는 현재 "remember me" 인증 토큰을 저장하기 위한 nullable, VARCHAR(100)와 동등한 컬럼을 생성합니다.

$table->rememberToken();

set()

set 메서드는 주어진 유효 값 목록으로 SET과 동등한 컬럼을 생성합니다.

$table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements()

smallIncrements 메서드는 자동 증가하는 UNSIGNED SMALLINT와 동등한 컬럼을 기본 키로 생성합니다.

$table->smallIncrements('id');

smallInteger()

smallInteger 메서드는 SMALLINT와 동등한 컬럼을 생성합니다.

$table->smallInteger('votes');

softDeletesTz()

softDeletesTz 메서드는 nullable deleted_at TIMESTAMP(타임존 포함)과 동등한 컬럼을 선택적 정밀도(전체 자릿수)와 함께 추가합니다. 이 컬럼은 Eloquent의 "소프트 삭제" 기능에서 필요한 deleted_at 타임스탬프를 저장하기 위해 사용됩니다.

$table->softDeletesTz($column = 'deleted_at', $precision = 0);

softDeletes()

softDeletes 메서드는 nullable deleted_at TIMESTAMP와 동등한 컬럼을 선택적 정밀도(전체 자릿수)와 함께 추가합니다. 이 컬럼은 Eloquent의 "소프트 삭제" 기능에서 필요한 deleted_at 타임스탬프를 저장하기 위해 사용됩니다.

$table->softDeletes($column = 'deleted_at', $precision = 0);

string()

string 메서드는 주어진 길이의 VARCHAR와 동등한 컬럼을 생성합니다.

$table->string('name', 100);

text()

text 메서드는 TEXT와 동등한 컬럼을 생성합니다.

$table->text('description');

timeTz()

timeTz 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는, 타임존 정보를 포함하는 TIME과 동등한 컬럼을 생성합니다.

$table->timeTz('sunrise', $precision = 0);

time()

time 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는 TIME과 동등한 컬럼을 생성합니다.

$table->time('sunrise', $precision = 0);

timestampTz()

timestampTz 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는, 타임존 정보를 포함하는 TIMESTAMP와 동등한 컬럼을 생성합니다.

$table->timestampTz('added_at', $precision = 0);

timestamp()

timestamp 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는 TIMESTAMP와 동등한 컬럼을 생성합니다.

$table->timestamp('added_at', $precision = 0);

timestampsTz()

timestampsTz 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는 created_atupdated_at 타임존 정보를 포함하는 TIMESTAMP와 동등한 컬럼을 생성합니다.

$table->timestampsTz($precision = 0);

timestamps()

timestamps 메서드는 선택적으로 정밀도(전체 자릿수)를 지정할 수 있는 created_atupdated_at TIMESTAMP와 동등한 컬럼을 생성합니다.

$table->timestamps($precision = 0);

tinyIncrements()

tinyIncrements 메서드는 자동 증가하는 UNSIGNED TINYINT와 동등한 컬럼을 기본 키로 생성합니다.

$table->tinyIncrements('id');

tinyInteger()

tinyInteger 메서드는 TINYINT와 동등한 컬럼을 생성합니다.

$table->tinyInteger('votes');

tinyText()

tinyText 메서드는 TINYTEXT와 동등한 컬럼을 생성합니다.

$table->tinyText('notes');

unsignedBigInteger()

unsignedBigInteger 메서드는 UNSIGNED BIGINT와 동등한 컬럼을 생성합니다.

$table->unsignedBigInteger('votes');

unsignedDecimal()

unsignedDecimal 메서드는 선택적으로 정밀도(전체 자릿수)와 소수점 자릿수를 지정할 수 있는 UNSIGNED DECIMAL과 동등한 컬럼을 생성합니다.

$table->unsignedDecimal('amount', $precision = 8, $scale = 2);

unsignedInteger()

unsignedInteger 메서드는 UNSIGNED INTEGER와 동등한 컬럼을 생성합니다.

$table->unsignedInteger('votes');

unsignedMediumInteger()

unsignedMediumInteger 메서드는 UNSIGNED MEDIUMINT와 동등한 컬럼을 생성합니다.

$table->unsignedMediumInteger('votes');

unsignedSmallInteger()

unsignedSmallInteger 메서드는 UNSIGNED SMALLINT와 동등한 컬럼을 생성합니다.

$table->unsignedSmallInteger('votes');

unsignedTinyInteger()

unsignedTinyInteger 메서드는 UNSIGNED TINYINT와 동등한 컬럼을 생성합니다.

$table->unsignedTinyInteger('votes');

uuidMorphs()

uuidMorphs 메서드는 {column}_id CHAR(36)과 동등한 컬럼, 그리고 {column}_type VARCHAR와 동등한 컬럼을 추가하는 편의 메서드입니다.

이 메서드는 UUID 식별자를 사용하는 다형적 Eloquent 연관관계에 필요한 컬럼을 정의할 때 사용합니다. 아래 예제에서는 taggable_idtaggable_type 컬럼이 생성됩니다.

$table->uuidMorphs('taggable');

uuid()

uuid 메서드는 UUID와 동등한 컬럼을 생성합니다.

$table->uuid('id');

year()

year 메서드는 YEAR와 동등한 컬럼을 생성합니다.

$table->year('birth_year');

컬럼 수정자

위에서 소개한 컬럼 타입 외에도, 데이터베이스 테이블에 컬럼을 추가할 때 사용할 수 있는 다양한 컬럼 "수정자(modifier)"가 있습니다. 예를 들어, 컬럼을 "nullable"로 만들고 싶다면 nullable 메서드를 사용할 수 있습니다.

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

Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});

아래 표는 사용 가능한 모든 컬럼 수정자를 정리한 것입니다. (여기에는 인덱스 수정자는 포함되지 않습니다.)

수정자설명
->after('column')다른 컬럼 "뒤에" 컬럼을 배치합니다 (MySQL).
->autoIncrement()INTEGER 컬럼을 자동 증가(기본 키)로 지정합니다.
->charset('utf8mb4')컬럼의 문자셋을 지정합니다 (MySQL).
->collation('utf8mb4_unicode_ci')컬럼의 정렬 규칙(collation)을 지정합니다 (MySQL/PostgreSQL/SQL Server).
->comment('my comment')컬럼에 주석을 추가합니다 (MySQL/PostgreSQL).
->default($value)컬럼의 "기본값"을 지정합니다.
->first()테이블에서 컬럼을 "첫 번째" 위치에 배치합니다 (MySQL).
->from($integer)자동 증가 필드(시퀀스)의 시작 값을 지정합니다 (MySQL / PostgreSQL).
->invisible()SELECT * 쿼리에서 컬럼을 "안 보이게" 숨깁니다 (MySQL).
->nullable($value = true)컬럼에 NULL 값 입력을 허용합니다.
->storedAs($expression)저장된 생성 컬럼(Stored Generated Column)을 만듭니다 (MySQL / PostgreSQL).
->unsigned()INTEGER 컬럼을 UNSIGNED로 지정합니다 (MySQL).
->useCurrent()TIMESTAMP 컬럼의 기본값을 CURRENT_TIMESTAMP로 지정합니다.
->useCurrentOnUpdate()레코드가 업데이트될 때 TIMESTAMP 컬럼 값을 CURRENT_TIMESTAMP로 지정합니다.
->virtualAs($expression)가상 생성 컬럼(Virtual Generated Column)을 만듭니다 (MySQL / PostgreSQL / SQLite).
->generatedAs($expression)명시적 시퀀스 옵션과 함께 식별자 컬럼을 생성합니다 (PostgreSQL).
->always()식별자 컬럼의 입력값과 시퀀스 값의 우선순위 규칙을 정합니다 (PostgreSQL).
->isGeometry()공간 컬럼 타입을 geometry로 지정합니다. 기본 타입은 geography입니다 (PostgreSQL).

기본값 표현식(Default Expressions)

default 수정자는 값 또는 Illuminate\Database\Query\Expression 인스턴스를 인수로 받을 수 있습니다. Expression 인스턴스를 사용하면 라라벨이 값을 따옴표로 감싸지 않고, 데이터베이스에서 제공하는 특수 함수나 표현식을 그대로 사용할 수 있습니다. 특히 JSON 컬럼에 기본값을 지정해야 할 때 유용합니다.

<?php

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

class CreateFlightsTable extends Migration
{
/**
* 마이그레이션을 실행합니다.
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
}

[!NOTE] 기본값 표현식 지원 여부는 사용하는 데이터베이스 드라이버, 데이터베이스 버전, 그리고 해당 필드의 타입에 따라 달라집니다. 자세한 내용은 각 데이터베이스의 공식 문서를 참고하세요.

컬럼 순서(Column Order)

MySQL 데이터베이스를 사용하는 경우, after 메서드를 사용하여 기존 컬럼 "뒤에" 새로운 컬럼들을 추가할 수 있습니다.

$table->after('password', function ($table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});

컬럼 수정하기

사전 준비(Prerequisites)

컬럼을 수정하기 전에, Composer 패키지 매니저를 사용하여 doctrine/dbal 패키지를 설치해야 합니다. Doctrine DBAL 라이브러리는 컬럼의 현재 상태를 파악하고, 변경 요청에 맞는 SQL 쿼리를 생성하기 위해 필요합니다.

composer require doctrine/dbal

timestamp 메서드로 생성한 컬럼을 수정하려면, 애플리케이션의 config/database.php 설정 파일에 아래 내용을 추가해야 합니다.

use Illuminate\Database\DBAL\TimestampType;

'dbal' => [
'types' => [
'timestamp' => TimestampType::class,
],
],

[!NOTE] 애플리케이션에서 Microsoft SQL Server를 사용하고 있다면, 반드시 doctrine/dbal:^3.0을 설치했는지 확인하세요.

컬럼 속성 수정하기

change 메서드를 사용하면 기존 컬럼의 타입이나 속성을 변경할 수 있습니다. 예를 들어, string 컬럼의 크기를 늘리고 싶을 때 사용할 수 있습니다. change 메서드의 동작 방식을 확인하기 위해, name 컬럼의 길이를 25에서 50으로 늘려보겠습니다. 이를 위해 컬럼의 새로운 상태를 정의한 후, change 메서드를 호출하면 됩니다.

Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});

또한, 컬럼을 nullable(널 허용)로 변경하는 것도 가능합니다.

Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->nullable()->change();
});

[!NOTE] 다음 컬럼 타입들에 대해 수정이 가능합니다: bigInteger, binary, boolean, date, dateTime, dateTimeTz, decimal, integer, json, longText, mediumText, smallInteger, string, text, time, unsignedBigInteger, unsignedInteger, unsignedSmallInteger, uuid. timestamp 컬럼 타입을 수정하려면 Doctrine 타입을 등록해야 합니다.

컬럼 이름 변경하기

컬럼명을 변경하려면, 스키마 빌더 블루프린트에서 제공하는 renameColumn 메서드를 사용할 수 있습니다. 컬럼명을 변경하기 전에, Composer 패키지 매니저로 doctrine/dbal 라이브러리를 설치했는지 반드시 확인하세요.

Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});

[!NOTE] 현재 enum 컬럼의 이름 변경은 지원되지 않습니다.

컬럼 제거하기

컬럼을 삭제하려면, 스키마 빌더 블루프린트의 dropColumn 메서드를 사용합니다. 만약 SQLite 데이터베이스를 사용하는 애플리케이션이라면, dropColumn 메서드를 사용하기 전에 Composer 패키지 매니저로 doctrine/dbal 패키지를 반드시 설치해야 합니다.

Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});

여러 개의 컬럼을 삭제하고 싶다면, 컬럼명들을 배열로 전달하면 됩니다.

Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});

[!NOTE] SQLite 데이터베이스를 사용할 경우, 하나의 마이그레이션에서 여러 컬럼을 한 번에 삭제하거나 수정하는 작업은 지원되지 않습니다.

사용 가능한 명령어 에일리어스

라라벨은 자주 사용하는 컬럼 유형을 간단하게 삭제할 수 있는 여러 유틸리티 메서드를 제공합니다. 아래 표에서 각 메서드의 역할을 확인할 수 있습니다.

명령어설명
$table->dropMorphs('morphable');morphable_idmorphable_type 컬럼을 삭제합니다.
$table->dropRememberToken();remember_token 컬럼을 삭제합니다.
$table->dropSoftDeletes();deleted_at 컬럼을 삭제합니다.
$table->dropSoftDeletesTz();dropSoftDeletes() 메서드의 에일리어스입니다.
$table->dropTimestamps();created_atupdated_at 컬럼을 삭제합니다.
$table->dropTimestampsTz();dropTimestamps() 메서드의 에일리어스입니다.

인덱스

인덱스 생성하기

라라벨 스키마 빌더는 다양한 유형의 인덱스를 지원합니다. 아래 예시는 새로운 email 컬럼을 생성하면서 해당 컬럼 값이 유일하도록 지정합니다. 인덱스를 생성하려면, 컬럼 정의에 unique 메서드를 체이닝하면 됩니다.

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

Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});

또는, 컬럼을 먼저 정의한 뒤 나중에 인덱스를 추가할 수도 있습니다. 이 경우, 스키마 빌더 블루프린트의 unique 메서드를 사용하면 됩니다. 인덱스를 적용할 컬럼명을 인자로 전달하면 됩니다.

$table->unique('email');

또한, 인덱스 메서드에 컬럼명을 배열로 전달하면 조합(composite) 인덱스도 만들 수 있습니다.

$table->index(['account_id', 'created_at']);

인덱스를 생성할 때, 라라벨은 기본적으로 테이블명, 컬럼명, 인덱스 유형을 결합하여 인덱스 이름을 자동 생성합니다. 하지만, 메서드에 두 번째 인자를 전달하여 직접 인덱스 이름을 지정할 수도 있습니다.

$table->unique('email', 'unique_email');

사용 가능한 인덱스 유형

라라벨의 스키마 빌더 블루프린트 클래스는 라라벨이 지원하는 각 인덱스 유형별로 메서드를 제공합니다. 각 인덱스 메서드는 인덱스 이름을 지정할 수 있는 두 번째 인자를 선택적으로 받을 수 있습니다. 만약 이름을 생략하면, 인덱스에 사용된 테이블명과 컬럼명, 인덱스 유형 등을 조합하여 자동 생성됩니다. 아래 표에서 각 인덱스 메서드에 대해 확인하실 수 있습니다.

명령어설명
$table->primary('id');기본키(primary key)를 추가합니다.
$table->primary(['id', 'parent_id']);복합키(composite key)를 추가합니다.
$table->unique('email');유니크 인덱스를 추가합니다.
$table->index('state');일반 인덱스를 추가합니다.
$table->fulltext('body');전문(fulltext) 인덱스를 추가합니다 (MySQL/PostgreSQL).
$table->fulltext('body')->language('english');특정 언어의 전문 인덱스를 추가합니다 (PostgreSQL).
$table->spatialIndex('location');공간(spatial) 인덱스를 추가합니다 (SQLite 제외).

인덱스 길이와 MySQL / MariaDB

라라벨은 기본적으로 utf8mb4 문자셋을 사용합니다. 만약 MySQL 5.7.7 미만 버전이나 MariaDB 10.2.2 미만 버전을 사용한다면, 마이그레이션이 생성하는 문자열의 기본 길이를 직접 지정해주어야 인덱스 생성에서 오류가 발생하지 않습니다. 이 경우, App\Providers\AppServiceProvider 클래스의 boot 메서드 안에서 Schema::defaultStringLength 메서드를 사용해 기본 문자열 길이를 설정할 수 있습니다.

use Illuminate\Support\Facades\Schema;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}

또 다른 대안으로, 데이터베이스의 innodb_large_prefix 옵션을 활성화할 수도 있습니다. 이 옵션 활성화 방법은 각 데이터베이스의 공식 문서를 참고하시기 바랍니다.

인덱스 이름 변경하기

인덱스의 이름을 변경하려면, 스키마 빌더 블루프린트에서 제공하는 renameIndex 메서드를 사용할 수 있습니다. 이 메서드는 첫 번째 인자로 기존 인덱스 이름, 두 번째 인자로 변경할 이름을 받습니다.

$table->renameIndex('from', 'to')

인덱스 삭제하기

인덱스를 삭제하려면, 해당 인덱스의 이름을 지정해야 합니다. 라라벨은 기본적으로 테이블명, 인덱싱된 컬럼명, 인덱스 유형을 조합하여 자동으로 인덱스 이름을 부여합니다. 다음 예시를 참고하세요.

명령어설명
$table->dropPrimary('users_id_primary');"users" 테이블의 기본키를 삭제합니다.
$table->dropUnique('users_email_unique');"users" 테이블의 유니크 인덱스를 삭제합니다.
$table->dropIndex('geo_state_index');"geo" 테이블의 일반 인덱스를 삭제합니다.
$table->dropSpatialIndex('geo_location_spatialindex');"geo" 테이블의 공간 인덱스를 삭제합니다 (SQLite 제외).

만약 컬럼 명 배열을 사용하여 인덱스를 삭제하는 메서드를 호출하면, 라라벨은 테이블명, 컬럼명, 인덱스 유형을 결합해 관례에 따라 인덱스 이름을 생성하여 삭제합니다.

Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // 'geo_state_index' 인덱스를 삭제합니다.
});

외래 키 제약조건(Foreign Key Constraints)

라라벨은 외래 키 제약조건 생성을 지원하여, 데이터베이스 수준에서 참조 무결성을 강제할 수 있습니다. 예를 들어, posts 테이블에 user_id 컬럼을 정의하고, 해당 컬럼이 users 테이블의 id 컬럼을 참조하도록 설정할 수 있습니다.

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

Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');

$table->foreign('user_id')->references('id')->on('users');
});

이 방식은 다소 장황하므로, 라라벨에서는 더 간편한 문법도 제공합니다. foreignId 메서드를 사용하여 컬럼을 생성하고, 예시처럼 코드를 간소화할 수 있습니다.

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});

foreignId 메서드는 UNSIGNED BIGINT에 해당하는 컬럼을 생성하고, constrained 메서드는 관례에 따라 참조할 테이블과 컬럼명을 자동으로 결정합니다. 만약 테이블명이 라라벨의 관례와 다르다면, constrained 메서드에 테이블명을 인자로 전달할 수 있습니다.

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained('users');
});

또한, 외래 키 제약조건의 "on delete"와 "on update" 동작을 직접 지정할 수도 있습니다.

$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');

이 동작을 위한 대체 문법도 제공됩니다.

메서드설명
$table->cascadeOnUpdate();갱신 시(cascade on update) 연쇄적으로 반영합니다.
$table->restrictOnUpdate();갱신 시(restrict on update) 제한합니다.
$table->cascadeOnDelete();삭제 시(cascade on delete) 연쇄적으로 반영합니다.
$table->restrictOnDelete();삭제 시(restrict on delete) 제한합니다.
$table->nullOnDelete();삭제 시 해당 컬럼 값을 null로 변경합니다.

추가적인 컬럼 수정자는 반드시 constrained 메서드보다 먼저 호출해야 합니다.

$table->foreignId('user_id')
->nullable()
->constrained();

외래 키 삭제하기

외래 키 제약조건을 삭제하려면, 삭제할 외래 키의 이름을 인자로 하여 dropForeign 메서드를 사용하면 됩니다. 외래 키 제약조건의 이름은 인덱스 이름과 동일한 관례를 따릅니다. 즉, 테이블명과 컬럼명 조합 뒤에 "_foreign"이 붙습니다.

$table->dropForeign('posts_user_id_foreign');

또는, 외래 키를 가진 컬럼명을 배열 형태로 전달할 수도 있습니다. 이 배열을 기준으로 라라벨이 자동으로 제약조건 이름을 생성하여 삭제합니다.

$table->dropForeign(['user_id']);

외래 키 제약조건 활성화/비활성화

마이그레이션 내부에서 아래 메서드들을 사용해 외래 키 제약조건을 활성화하거나 비활성화할 수 있습니다.

Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

[!NOTE] SQLite는 기본적으로 외래 키 제약조건을 비활성화합니다. SQLite를 사용할 경우, 마이그레이션에서 외래 키를 생성하기 전에 반드시 외래 키 지원을 활성화해야 합니다. 또한, SQLite에서는 테이블 생성 시에만 외래 키를 지원하며, 테이블 수정 시에는 외래 키 제약조건을 지원하지 않습니다.

이벤트

편의를 위해, 각 마이그레이션 작업 시 아래와 같은 이벤트가 발생합니다. 이들 이벤트는 모두 기본 클래스인 Illuminate\Database\Events\MigrationEvent를 확장합니다.

클래스설명
Illuminate\Database\Events\MigrationsStarted여러 개의 마이그레이션이 실행되기 직전 발생합니다.
Illuminate\Database\Events\MigrationsEnded여러 개의 마이그레이션 실행이 끝난 시점에 발생합니다.
Illuminate\Database\Events\MigrationStarted단일 마이그레이션이 실행되기 직전 발생합니다.
Illuminate\Database\Events\MigrationEnded단일 마이그레이션 실행이 끝난 시점에 발생합니다.