04강: 데이터베이스 시더(Seeder) & 1,000권 도서 한 방 구축 (migrate:fresh --seed)
실습 프로젝트: 지니샵(JinyShop) 온라인 도서 쇼핑몰
주제: 계층형 카테고리 시딩, 1,000권 도서 대량 시더(BookSeeder),migrate:fresh --seed원클릭 데이터베이스 초기화
등장인물: 🐱 지니(시니어 멘토), 👧 도로시(주니어 개발자), 🐶 토토(개발 보조견)
공식 문서 연계: 시딩 (Seeding)
💬 1. 지니와 도로시의 티키타카 회의
👧 도로시: “지니! 우리가 만든 카테고리, 저자, 출판사, 책 팩토리들을 하나의 완벽한 서점으로 조립하려면 어떻게 해야 해요? 새 팀원이 프로젝트를 내려받았을 때 터미널에서 명령어 딱 한 번만 치면 1,000권의 알록달록한 책들과 카테고리가 촤르륵 세팅되게 만들 수 있을까요?”
🐱 지니: “물론이지 도로시! 라라벨의 데이터베이스 시더(Database Seeder)가 바로 그 마법 지휘봉이란다! DatabaseSeeder 클래스에 실행 순서를 정해두고, php artisan migrate:fresh --seed 명령어를 실행하면, 기존 테이블을 깨끗이 밀어버리고(fresh) 마이그레이션과 1,000권 시딩을 단 3초 만에 완벽하게 적재해 준단다!”
🐶 토토: “멍멍! 대량 데이터를 넣을 때는 메모리가 터지지 않게 청크(Chunk) 단위로 쪼개어 시딩하는 것이 꿀팁이다멍!”
🎯 2. 실습 목표 및 서점 시나리오
- 서점의 실제 대분류/중분류 카테고리를 체계적으로 적재하는
CategorySeeder를 작성합니다. - 20개 출판사, 50명의 저자, 1,000권의 다채로운 도서를 대량 생성하는
BookSeeder를 구현합니다. php artisan migrate:fresh --seed명령어로 완벽하게 초기화된 서점 데이터베이스를 구축합니다.
🛠️ 3. 단계별 실습 절차 (Step-by-Step)
[Step 1] 개별 시더 파일 생성
아티산 명령어로 역할별 시더 클래스를 생성합니다:
php artisan make:seeder CategorySeeder
php artisan make:seeder BookSeeder
[Step 2] CategorySeeder.php 계층형 카테고리 트리 작성
database/seeders/CategorySeeder.php에 대분류와 하위 소분류 트리를 정의합니다:
namespace Database\Seeders;
use App\Models\Category;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
class CategorySeeder extends Seeder
{
public function run(): void
{
$catalog = [
'IT / 컴퓨터' => [
'웹 프로그래밍 (PHP, JS, Python)',
'모바일 앱 개발 (Flutter, Swift)',
'인공지능 및 딥러닝',
'클라우드 및 DevOps',
'데이터베이스 및 SQL',
],
'경제 / 경영' => [
'재테크 및 투자',
'스타트업 창업 스토리',
'마케팅 및 브랜딩',
],
'인문 / 사회' => [
'서양 철학',
'역사와 문화',
'심리학 이야기',
],
'소설 / 문학' => [
'한국 현대 소설',
'SF 및 판타지',
'에세이와 시',
],
];
$order = 1;
foreach ($catalog as $parentName => $subCategories) {
// 대분류 생성
$parent = Category::create([
'name' => $parentName,
'slug' => Str::slug($parentName),
'order_num' => $order++,
'parent_id' => null,
]);
// 소분류 생성
foreach ($subCategories as $subName) {
Category::create([
'name' => $subName,
'slug' => Str::slug($subName),
'order_num' => $order++,
'parent_id' => $parent->id,
]);
}
}
}
}
[Step 3] BookSeeder.php 1,000권 도서 대량 시딩 작성
database/seeders/BookSeeder.php에서 출판사, 저자를 미리 생성하고 1,000권의 도서를 골고루 분배하여 생성합니다:
namespace Database\Seeders;
use App\Models\Author;
use App\Models\Book;
use App\Models\Category;
use App\Models\Publisher;
use Illuminate\Database\Seeder;
class BookSeeder extends Seeder
{
public function run(): void
{
// 1. 기본 출판사 15개 생성
$publishers = Publisher::factory()->count(15)->create();
// 2. 기본 저자 40명 생성
$authors = Author::factory()->count(40)->create();
// 3. 기존 등록된 소분류 카테고리 수집
$categories = Category::whereNotNull('parent_id')->get();
$this->command->info('📚 지니샵 1,000권의 도서 데이터를 시딩하는 중입니다...');
// 4. 도서 1,000권 대량 생성 (할인 도서 및 전자책 비율 분배)
for ($i = 0; $i < 1000; $i++) {
$author = $authors->random();
$publisher = $publishers->random();
$category = $categories->random();
$factory = Book::factory()->for($author)->for($publisher)->for($category);
// 20% 확률로 10~30% 할인 도서 적용
if (fake()->boolean(20)) {
$factory = $factory->discounted(fake()->randomElement([10, 15, 20, 30]));
}
// 30% 확률로 전자책(eBook) 적용
if (fake()->boolean(30)) {
$factory = $factory->ebook();
}
// 5% 확률로 품절 도서 적용
if (fake()->boolean(5)) {
$factory = $factory->outOfStock();
}
$factory->create();
}
$this->command->info('✅ 1,000권의 도서 시딩 완료!');
}
}
[Step 4] DatabaseSeeder.php 통합 연결
database/seeders/DatabaseSeeder.php에서 시더 실행 순서를 조립합니다:
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
// 1. 카테고리 먼저 적재
$this->call(CategorySeeder::class);
// 2. 출판사, 저자 및 1,000권 도서 적재
$this->call(BookSeeder::class);
}
}
[Step 5] 원클릭 초기화 실행 (migrate:fresh --seed)
터미널에서 마법의 명령어를 가동합니다:
php artisan migrate:fresh --seed
터미널 출력:
Dropped all tables successfully. INFO Running migrations. 2026_09_25_000001_create_publishers_table .................... 12ms DONE 2026_09_25_000002_create_authors_table ....................... 10ms DONE 2026_09_25_000003_create_categories_table .................... 11ms DONE 2026_09_25_000004_create_books_table ......................... 18ms DONE INFO Seeding database. 📚 지니샵 1,000권의 도서 데이터를 시딩하는 중입니다... ✅ 1,000권의 도서 시딩 완료!
[Step 6] 적재된 데이터 검증
Tinker로 시딩 결과를 즉시 검증합니다:
php artisan tinker --execute="echo '총 도서 수: ' . App\Models\Book::count() . '권 / 전자책: ' . App\Models\Book::where('format', 'ebook')->count() . '권';"
출력:
총 도서 수: 1000권 / 전자책: 약 300권
🔍 4. 라라벨 공식 문서 원리 심층 분석 (Deep Dive)
운영 서버에서의 migrate:fresh 방지 안전장치
migrate:fresh는 기존 테이블과 데이터를 무조건 삭제하기 때문에, 만약 실제 상용(Production) 서버에서 실수로 실행하면 서비스 전체 데이터가 소실되는 대참사가 일어납니다.- 라라벨은
APP_ENV=production환경에서 파괴적인 명령어가 실행되면 자동으로 경고 프롬프트(Do you really wish to run this command?)를 띄우고 기본 실행을 차단하는 든든한 방패를 내장하고 있습니다.
🐶 5. 토토의 트러블슈팅 & 주의사항
🐶 토토의 멍멍 가이드!
- 시더를 실행하다가
Foreign key constraint fails에러가 나요!
자식 테이블을 시딩하기 전에 부모 데이터(CategorySeeder)가 먼저 실행되었는지DatabaseSeeder.php의$this->call()순서를 꼭 점검하라멍!
💡 6. 4강 자가진단 과제
Book::where('status', 'out_of_stock')->count()로 품절 처리된 도서 수를 조회해 보세요.Book::whereNotNull('sale_price')->count()로 할인 중인 도서 수를 확인해 보세요.- 이제 다음 5주차에서 이 1,000권의 도서를 브라우저 화면에서 페이징하고 정렬할 준비가 완벽히 끝났습니다!