마이그레이션 파일에 컬럼을 추가하고 DB에 테이블 생성하기

포스트 썸네일 이미지

이전 포스트에서 -mrc 옵션을 이용해 모델과 마이그레이션, 컨트롤러를 명령어 한 줄로 뚝딱 만들어보았다.

오늘은 그렇게 생성된 마이그레이션 파일의 뼈대를 직접 수정하여 우리가 원하는 컬럼들을 추가하고, 실제 DB에 반영하는 과정을 다루어 보겠다.




이전 포스트




posts 테이블에 추가할 컬럼들


create_posts_table.php

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->string('message', 300);
        $table->timestamps();
    });
}

생성한 create_posts_table.php 파일을 이렇게 수정한다.

idtimestamps는 원래 있었고, 그 사이에 2줄이 추가됐다.





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

constrained() 메서드는 외래 키 제약 조건을 정의하는 마이그레이션에서 사용된다.

이 메서드를 사용하면 외래 키 제약 조건을 정의할 때 편리하게 사용할 수 있다.


위의 코드는 user_id라는 외래 키 컬럼을 생성하고, 이 컬럼이 users 테이블의 id 컬럼을 참조한다는 것을 정의한다.

즉, user_id 컬럼은 users 테이블의 id 컬럼을 참조하는 외래 키이며, 참조 무결성을 위해 자동으로 외래 키 제약 조건이 생성된다.


※ 주의: constrained() 메서드는 데이터베이스 수준에서 외래 키 제약 조건을 설정하는 것일 뿐이므로, 라라벨 PHP 코드에서 데이터 관계를 편리하게 조회하려면 모델(Model) 파일 내부에 hasManybelongsTo 같은 관계 정의 코드를 반드시 별도로 명시해 주어야 한다.


constrained() 메서드를 호출할 때 인수를 전달하지 않으면 (괄호 안에 아무것도 쓰지 않으면),

Laravel은 기본적으로 외래 키 이름에서 _id를 뗀 단어를 복수형으로 변환하여 참조할 테이블을 자동으로 유추한다. (예: user_idusers 테이블)

따라서 테이블 이름이 규칙에 맞다면 명시적으로 테이블 이름을 지정하는 것은 선택 사항이다.

만약 constrained('users')와 같이 명시적으로 지정하면 코드를 더 명확하게 만들어 가독성을 높이는 데 도움이 될 수 있다. (하지만 여기서는 생략했다.)


거기에 더해 cascadeOnDelete() 메서드도 추가했다.

cascadeOnDelete를 사용하지 않으면 부모인 user 레코드를 삭제할 때, 자식 레코드(예: 해당 유저가 쓴 글)가 존재한다면 데이터베이스 무결성이 깨지므로 SQLSTATE[23000] 에러가 발생한다.

SQLSTATE[23000] 에러는 데이터베이스에서 무결성 제약 조건을 위반했을 때 발생하는 일반적인 SQL 예외 코드다.


cascadeOnDelete()를 사용하여 외래 키 제약 조건을 설정하면, 해당 외래 키가 참조하는 행(부모)이 삭제될 때 연관된 행(자식)도 함께 삭제된다.

이는 데이터베이스에서 "CASCADE" 제약 조건과 동등한 효과를 가진다.


예를 들어, users 테이블에서 어떤 회원이 탈퇴하면(계정이 삭제되면), 해당 회원의 user_id를 참조하는 posts 테이블의 글들도 함께 삭제된다.

무슨 말이냐면, A라는 사용자가 10개의 글을 남겼는데, A라는 사용자의 계정이 삭제되면 그 계정으로 남겼던 10개의 글도 자동으로 삭제가 된다는 말이다.

따라서 이 메서드를 사용하면 연관된 데이터를 자동으로 청소할 수 있어서 데이터 참조 무결성을 유지하기가 훨씬 쉬워진다.





$table->string('message', 300);

메시지의 내용을 저장하는 문자열 컬럼이다.

여기서는 최대 300자까지 저장할 수 있게 설정해 놨다.


$table->string(...)은 데이터베이스에서 가변 길이 문자열을 저장하는 VARCHAR 타입을 생성하는 코드다.

글의 제목, 이메일 주소, 댓글과 같은 짧은 메시지, 비밀번호 같은 일반적인 글자(문자열)를 저장할 때 사용한다.


이 칸에 저장할 수 있는 문자의 최대 길이를 300자로 제한하도록 설정했는데, 이렇게 항상 글자 수 제한을 설정해 두는 것이 좋다.

제한을 두는 이유에는 다음과 같은 것들이 있다.


  1. 악의적인 해커가 매크로 프로그램을 돌려서 댓글 한 칸에 수십억 개의 글자(몇 GB 용량의 텍스트)를 강제로 밀어 넣는 공격을 할 수 있다. 그러면 순식간에 하드디스크 용량이 가득 차서 서버와 데이터베이스가 뻗어버리게 된다. string('message', 300)처럼 락을 걸어두면 이런 무식한 공격을 데이터베이스 입구에서 컷할 수 있다.
  2. 데이터베이스는 데이터를 정렬하거나 계산할 때 메모리(RAM)를 사용한다. 글자 수 제한이 있을 경우에는 데이터베이스가 "이 칸은 아무리 커봤자 300자구나"라고 미리 계산하고 사이즈를 예측하여 메모리를 딱 필요한 만큼만 영리하게 나누어 쓴다.
  3. 휴대폰 번호나 우편번호처럼 글자 수 제한이 명확한 컬럼에 제한을 두면, 엉뚱하게 수백 자짜리 쓰레기 데이터가 실수로 흘러 들어와 데이터베이스가 지저분해지는 것을 원천 봉쇄할 수 있다.
  4. 웹사이트를 만들 때 댓글 공간을 만들어 두었는데, 어떤 사용자가 제한이 없다고 해서 5,000자짜리 댓글을 적어버리면 웹사이트 레이아웃이 엉망진창이 된다. 데이터베이스에서 글자 수를 딱 잡아주면 화면을 설계할 때 디자인 가이드라인을 지키기가 훨씬 수월해진다.


나중에 긴 장문의 글을 저장하는 게시판이나 블로그를 만들 때는 string 대신 text라는 메서드를 사용해야 한다.





make app #컨테이너 안으로 들어간다.
php artisan migrate

VSCode의 터미널에서 이 명령어들을 실행한다.




명령어를 실행해서 posts 테이블이 생성된 모습

그러면 데이터베이스에 posts 테이블이 생성된다.


캡처 이미지에서는 컨테이너 안으로 들어갈 때, make app이 아닌 make bash 명령어를 입력했는데, 어느 쪽이든 상관없다.

php artisan migrate 명령어는 프로젝트 폴더(src/) 안에 파일을 새로 만드는 명령어가 아니기 때문이다.




캡처 이미지 속의 VSCode 익스텐션은 이 포스트에서 소개했었다.





users 테이블의 마이그레이션 파일도 살펴보자


users 테이블을 생성한 마이그레이션 파일에서도 몇 개의 코드들을 살펴보겠다.



->unique();

해당 컬럼에 똑같은 값이 중복해서 들어오는 것을 데이터베이스 레벨에서 원천 봉쇄한다.

회원의 아이디나 이메일 주소, 주민등록번호, 폰 번호 등의 컬럼에 사용한다.



->nullable();

기본적으로 라라벨의 모든 컬럼은 값을 무조건 채워야 하는 '필수 입력' 상태다.

하지만 이 메서드를 붙이면 값을 넣지 않고 비워두어도(NULL) 데이터베이스가 에러를 내지 않고 통과시켜 준다.

회원가입 시 필수 입력 사항이 아닌 '프로필 한 줄 소개' 등이나 글을 작성할 때 첨부할 이미지 등의 컬럼에 사용한다.



->index();

데이터베이스가 해당 컬럼을 기준으로 데이터를 빛의 속도로 찾아낼 수 있도록 뒤편에 '색인(Index) 주소록'을 생성하라는 명령이다.

WHERE 조건문이나 검색창에서 매일같이 단골로 검색 조건에 들어가는 컬럼(예: 글 카테고리, 작성일자, 상태 값 등)에 사용한다.





그 외 마이그레이션 관련 명령어


위에서 사용한 php artisan migrate 이외의 명령어들도 몇 개 소개하고 글을 마치겠다.


마이그레이션 파일의 내부에는 up 메서드와 down 메서드가 있다.

up은 실행(테이블 작성)이고, down은 php artisan migrate를 실행하기 전의 상태로 되돌린다.

즉, 만들었던 테이블을 삭제하는 것이다.




php artisan migrate:rollback

이 명령어를 실행하면 down 메서드가 실행되면서 원래대로 돌아온다.

연속해서 사용하면 방금 전에 실행한 것뿐만 아니라 그전에 php artisan migrate를 실행했던 것도 취소시킬 수 있다.




php artisan migrate:fresh

이 명령어는 현재 데이터베이스에 있는 모든 테이블을 묻지도 따지지도 않고 통째로 완전히 삭제해 버린 뒤, database/migrations/ 폴더에 있는 설계도들을 처음부터 다시 새롭게 실행(migrate)한다.

그러니 개발 중에만 사용해야 할 명령어다.

실제로 배포해서 운영 중인 웹사이트에서 실행해서는 안된다.


마이그레이션 파일 내부 코드가 어떻게 짜여 있든 상관없이 데이터베이스 전체를 깨끗하게 비워버리기 때문에, 외래 키 제약 조건 등으로 인해 꼬여있던 에러들이 무조건 100% 한 방에 해결된다.

개발용 가짜 데이터를 넣는 시딩 명령어인 --seed 옵션을 붙여서 php artisan migrate:fresh --seed 형태로 자주 쓴다.




라라벨의 마이그레이션은 단순히 데이터베이스 테이블을 만드는 것을 넘어, 팀원들과 데이터베이스 구조를 코드로 공유하고 안전하게 형상 관리를 할 수 있도록 돕는 아주 강력한 도구다.

오늘 알아본 각종 속성(unique, nullable, index)과 rollback, fresh 명령어들의 주의사항을 잘 숙지해 두시면, 개발 도중 데이터 구조가 바뀌더라도 유연하고 안전하게 대처할 수 있을 것이다.


데이터베이스 설계도가 깔끔하게 준비되었으니, 다음 포스트에서는 이 테이블에 데이터를 채우고 가공하는 컨트롤러Controller의 실제 로직 작성법을 다뤄보겠다.




다음 포스트

이 글이 도움이 됐거나 유익했다면 스크롤을 조금만 더 내려서 댓글을 남겨주세요. (비로그인도 가능합니다!)
응원이나 피드백이 담긴 댓글은 제가 계속 블로그를 해나갈 수 있는 원동력이 됩니다. 😊

지인에게 보여주고 싶은 글이었다면 URL을 복사해서 메신저나 소셜 미디어에 공유해 주세요.
이전 포스트 다음 포스트

댓글 쓰기

0 Comments

문의하기 양식