> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 数据库填充（Seeding）

> 介绍如何使用 Laravel 的填充功能向数据库中写入用于开发和测试的示例数据。

## 什么是 Seeding

Seeding（填充）是向数据库写入示例数据或初始数据的机制。

在搭建开发环境或运行自动化测试时，通常需要预先有一定的数据。由于每次手动输入数据非常繁琐，可以将其整理为可重复执行的 Seeder。

Seeder 类存放在 `database/seeders` 目录下。默认会提供一个 `DatabaseSeeder` 类。

```mermaid theme={null}
flowchart TD
    A["php artisan db:seed"] --> B["DatabaseSeeder::run()"]
    B --> C["UserSeeder::run()"]
    B --> D["PostSeeder::run()"]
    C --> E["向 users 表插入数据"]
    D --> F["向 posts 表插入数据"]
```

## 创建 Seeder

使用 `make:seeder` Artisan 命令生成一个新的 Seeder 类。

```shell theme={null}
php artisan make:seeder UserSeeder
```

生成的文件会放在 `database/seeders/UserSeeder.php`。

```php theme={null}
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
    /**
     * 执行 Seeder
     */
    public function run(): void
    {
        // 在这里编写数据写入逻辑
    }
}
```

## 编写 Seeder

在 `run()` 方法中编写数据写入逻辑。你可以使用 DB 门面或 Eloquent 模型来插入数据。

### 使用 DB 门面

```php theme={null}
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        DB::table('users')->insert([
            [
                'name' => '山田太郎',
                'email' => 'taro@example.com',
                'password' => Hash::make('password'),
                'created_at' => now(),
                'updated_at' => now(),
            ],
            [
                'name' => '铃木花子',
                'email' => 'hanako@example.com',
                'password' => Hash::make('password'),
                'created_at' => now(),
                'updated_at' => now(),
            ],
        ]);
    }
}
```

### 使用 Eloquent 模型

```php theme={null}
use App\Models\User;
use Illuminate\Support\Facades\Hash;

public function run(): void
{
    User::create([
        'name' => '管理员',
        'email' => 'admin@example.com',
        'password' => Hash::make('password'),
    ]);
}
```

<Info>
  Seeding 执行期间，批量赋值保护会自动被禁用。你无需关心 `$fillable` 或 `$guarded` 的配置就可以插入数据。
</Info>

## 与模型工厂结合使用

如果需要大量测试数据，与[模型工厂](/zh/eloquent)结合使用会非常方便。工厂能够批量生成带有随机字段的假数据。

```php theme={null}
use App\Models\User;
use App\Models\Post;

public function run(): void
{
    // 创建 10 位用户
    User::factory(10)->create();

    // 为每位用户创建 3 条帖子
    User::factory(5)
        ->hasPosts(3)
        ->create();
}
```

<Tip>
  关于工厂的详细用法请参阅 Eloquent 工厂文档。
</Tip>

## DatabaseSeeder 的用法

`DatabaseSeeder` 是统一管理多个 Seeder 的入口。使用 `call()` 方法指定要执行的 Seeder。

```php theme={null}
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            PostSeeder::class,
            CommentSeeder::class,
        ]);
    }
}
```

Seeder 会按照传给 `call()` 的顺序执行。如果存在外键约束，请让被引用的表先填充（如：`users` → `posts`）。

## 运行 Seeder

### 运行所有 Seeder

```shell theme={null}
php artisan db:seed
```

将会调用 `DatabaseSeeder`，然后按顺序执行通过 `call()` 指定的 Seeder。

### 只执行特定 Seeder

使用 `--class` 选项可以指定要执行的 Seeder 类。

```shell theme={null}
php artisan db:seed --class=UserSeeder
```

## 与迁移一起执行

在 `migrate:fresh` 命令上添加 `--seed` 选项，可以先重建所有数据表，然后统一执行 Seeder。

```shell theme={null}
php artisan migrate:fresh --seed
```

如果只需执行特定 Seeder，可以使用 `--seeder` 选项。

```shell theme={null}
php artisan migrate:fresh --seed --seeder=UserSeeder
```

<Warning>
  `migrate:fresh` 会删除并重建所有表，现有数据都会丢失，因此不要在生产环境中使用。
</Warning>

## 在生产环境中执行

在生产环境执行 Seeding 时会出现确认提示。如果不需要确认，可以使用 `--force` 标记。

```shell theme={null}
php artisan db:seed --force
```

<Warning>
  在生产环境执行 Seeding 可能造成数据被覆盖或丢失。执行前请务必做好备份。
</Warning>

## 抑制模型事件

如果希望在 Seeding 期间阻止 `creating`、`created` 等模型事件被触发，可以使用 `WithoutModelEvents` trait。

```php theme={null}
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;

class DatabaseSeeder extends Seeder
{
    use WithoutModelEvents;

    public function run(): void
    {
        $this->call([
            UserSeeder::class,
        ]);
    }
}
```

该 trait 也会作用于通过 `call()` 调用的子 Seeder。

## 实战示例：博客应用的 Seeder

以一个包含用户与帖子的博客应用为例，来搭建初始数据。

```php theme={null}
// database/seeders/UserSeeder.php
class UserSeeder extends Seeder
{
    public function run(): void
    {
        User::factory(10)->create();
    }
}

// database/seeders/PostSeeder.php
class PostSeeder extends Seeder
{
    public function run(): void
    {
        // 为每位用户创建 2 到 5 条帖子
        User::all()->each(function ($user) {
            Post::factory(rand(2, 5))->create([
                'user_id' => $user->id,
            ]);
        });
    }
}

// database/seeders/DatabaseSeeder.php
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            PostSeeder::class, // 在 users 之后执行
        ]);
    }
}
```

执行步骤：

```shell theme={null}
php artisan migrate:fresh --seed
```

## 下一步

<Card title="Eloquent 入门" icon="database" href="/zh/eloquent">
  学习如何通过 Eloquent ORM 获取和操作已通过 Seeder 写入的数据。
</Card>


## Related topics

- [数据库迁移](/zh/migrations.md)
- [数据库配置](/zh/database.md)
- [Eloquent 工厂](/zh/eloquent-factories.md)
- [数据库测试](/zh/database-testing.md)
- [并发处理](/zh/concurrency.md)
