种子数据生成器Skill seed-data-generator

种子数据生成器是一款专门用于数据库开发和测试的工具,能够生成高质量、现实世界的测试数据。它支持多种编程语言(如JavaScript、Python、Ruby)和数据库系统,包括SQL和ORM基的种子生成,确保引用完整性、数据多样性和可重复性。适用于数据库开发、测试、演示以及性能测试等场景。关键词:测试数据、数据库、SQL、ORM、Faker、种子生成、引用完整性、JavaScript、Python、Ruby。

测试 0 次安装 0 次浏览 更新于 3/11/2026

名称: seed-data-generator 描述: 为数据库开发、测试和演示生成现实世界的测试数据。

种子数据生成器技能

为数据库开发、测试和演示生成现实世界的测试数据。

指令

您是测试数据生成专家。当调用时:

  1. 分析架构

    • 识别表和关系
    • 理解列类型和约束
    • 检测外键依赖
    • 识别数据模式(如电子邮件、电话、日期等)
  2. 生成现实世界数据

    • 使用faker库生成现实数据
    • 维持引用完整性
    • 遵循业务逻辑约束
    • 创建多样但现实的场景
  3. 种子数据库

    • 按正确顺序插入数据(尊重外键)
    • 处理不同数据库系统
    • 提供SQL和基于ORM的种子生成器
    • 支持增量播种
  4. 自定义生成

    • 允许指定数量
    • 支持不同数据场景(边界情况、正常路径)
    • 启用数据关系自定义
    • 提供可重复种子(带随机种子值)

支持工具

  • JavaScript/TypeScript: Faker.js, Chance.js, Casual
  • Python: Faker, Factory Boy, Mimesis
  • Ruby: Faker, FactoryBot
  • 原始SQL: 生成INSERT语句
  • ORMs: Prisma, TypeORM, Sequelize, Django, Rails

使用示例

@seed-data-generator
@seed-data-generator --count 100
@seed-data-generator --table users
@seed-data-generator --scenario e-commerce
@seed-data-generator --realistic-relationships

SQL种子数据

PostgreSQL - 基本插入

-- seed/001_users.sql
INSERT INTO users (username, email, password_hash, active, created_at)
VALUES
  ('john_doe', 'john@example.com', '$2b$10$...', true, '2024-01-15 10:00:00'),
  ('jane_smith', 'jane@example.com', '$2b$10$...', true, '2024-01-16 11:30:00'),
  ('bob_wilson', 'bob@example.com', '$2b$10$...', true, '2024-01-17 09:15:00'),
  ('alice_brown', 'alice@example.com', '$2b$10$...', false, '2024-01-18 14:45:00'),
  ('charlie_davis', 'charlie@example.com', '$2b$10$...', true, '2024-01-19 16:20:00');

-- seed/002_categories.sql
INSERT INTO categories (name, slug, parent_id)
VALUES
  ('Electronics', 'electronics', NULL),
  ('Computers', 'computers', 1),
  ('Laptops', 'laptops', 2),
  ('Desktops', 'desktops', 2),
  ('Accessories', 'accessories', 1),
  ('Clothing', 'clothing', NULL),
  ('Men', 'men', 6),
  ('Women', 'women', 6);

-- seed/003_products.sql
INSERT INTO products (name, description, price, stock_quantity, category_id, created_at)
VALUES
  (
    'MacBook Pro 16"',
    'Powerful laptop with M3 chip, 16GB RAM, 512GB SSD',
    2499.99,
    15,
    3,
    NOW()
  ),
  (
    'Dell XPS 13',
    'Compact laptop with Intel i7, 16GB RAM, 512GB SSD',
    1299.99,
    20,
    3,
    NOW()
  ),
  (
    'Gaming Desktop',
    'High-performance desktop with RTX 4080, 32GB RAM',
    2999.99,
    8,
    4,
    NOW()
  ),
  (
    'Wireless Mouse',
    'Ergonomic wireless mouse with precision tracking',
    29.99,
    100,
    5,
    NOW()
  ),
  (
    'Mechanical Keyboard',
    'RGB mechanical keyboard with Cherry MX switches',
    149.99,
    45,
    5,
    NOW()
  );

-- seed/004_orders.sql
INSERT INTO orders (user_id, total_amount, status, created_at)
VALUES
  (1, 2529.98, 'completed', '2024-01-20 10:30:00'),
  (2, 1299.99, 'completed', '2024-01-21 14:15:00'),
  (3, 179.98, 'processing', '2024-01-22 09:45:00'),
  (1, 2999.99, 'pending', '2024-01-23 16:00:00'),
  (4, 29.99, 'completed', '2024-01-24 11:20:00');

-- seed/005_order_items.sql
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES
  -- Order 1
  (1, 1, 1, 2499.99),
  (1, 4, 1, 29.99),
  -- Order 2
  (2, 2, 1, 1299.99),
  -- Order 3
  (3, 4, 1, 29.99),
  (3, 5, 1, 149.99),
  -- Order 4
  (4, 3, 1, 2999.99),
  -- Order 5
  (5, 4, 1, 29.99);

使用函数生成的种子

-- 生成随机用户
CREATE OR REPLACE FUNCTION generate_users(count INTEGER)
RETURNS void AS $$
DECLARE
  i INTEGER;
BEGIN
  FOR i IN 1..count LOOP
    INSERT INTO users (username, email, password_hash, active, created_at)
    VALUES (
      'user_' || i,
      'user' || i || '@example.com',
      '$2b$10$fakehashedpassword',
      random() > 0.1, -- 90% 活跃
      NOW() - (random() * 365 || ' days')::INTERVAL
    );
  END LOOP;
END;
$$ LANGUAGE plpgsql;

-- 生成随机产品
CREATE OR REPLACE FUNCTION generate_products(count INTEGER)
RETURNS void AS $$
DECLARE
  i INTEGER;
  categories INTEGER[];
BEGIN
  SELECT ARRAY_AGG(id) INTO categories FROM categories;

  FOR i IN 1..count LOOP
    INSERT INTO products (name, description, price, stock_quantity, category_id, created_at)
    VALUES (
      'Product ' || i,
      'Description for product ' || i,
      (random() * 1000 + 10)::NUMERIC(10,2),
      (random() * 100)::INTEGER,
      categories[1 + floor(random() * array_length(categories, 1))::INTEGER],
      NOW() - (random() * 180 || ' days')::INTERVAL
    );
  END LOOP;
END;
$$ LANGUAGE plpgsql;

-- 生成随机订单
CREATE OR REPLACE FUNCTION generate_orders(count INTEGER)
RETURNS void AS $$
DECLARE
  i INTEGER;
  user_ids INTEGER[];
  product_ids INTEGER[];
  order_id INTEGER;
  item_count INTEGER;
  j INTEGER;
  total NUMERIC(10,2);
BEGIN
  SELECT ARRAY_AGG(id) INTO user_ids FROM users WHERE active = true;
  SELECT ARRAY_AGG(id) INTO product_ids FROM products WHERE stock_quantity > 0;

  FOR i IN 1..count LOOP
    -- 随机项目数 (1-5)
    item_count := 1 + floor(random() * 5)::INTEGER;
    total := 0;

    INSERT INTO orders (user_id, total_amount, status, created_at)
    VALUES (
      user_ids[1 + floor(random() * array_length(user_ids, 1))::INTEGER],
      0, -- 将在添加项目后更新
      (ARRAY['pending', 'processing', 'completed', 'cancelled'])[1 + floor(random() * 4)::INTEGER],
      NOW() - (random() * 90 || ' days')::INTERVAL
    )
    RETURNING id INTO order_id;

    -- 添加订单项目
    FOR j IN 1..item_count LOOP
      DECLARE
        product_price NUMERIC(10,2);
        quantity INTEGER;
      BEGIN
        SELECT price INTO product_price
        FROM products
        WHERE id = product_ids[1 + floor(random() * array_length(product_ids, 1))::INTEGER];

        quantity := 1 + floor(random() * 3)::INTEGER;

        INSERT INTO order_items (order_id, product_id, quantity, price)
        VALUES (
          order_id,
          product_ids[1 + floor(random() * array_length(product_ids, 1))::INTEGER],
          quantity,
          product_price
        );

        total := total + (product_price * quantity);
      END;
    END LOOP;

    -- 更新订单总额
    UPDATE orders SET total_amount = total WHERE id = order_id;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

-- 用法
SELECT generate_users(100);
SELECT generate_products(50);
SELECT generate_orders(200);

JavaScript/TypeScript 种子生成器

Faker.js + Prisma

// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
import { faker } from '@faker-js/faker';

const prisma = new PrismaClient();

async function main() {
  console.log('播种数据库...');

  // 清除现有数据
  await prisma.orderItem.deleteMany();
  await prisma.order.deleteMany();
  await prisma.review.deleteMany();
  await prisma.product.deleteMany();
  await prisma.category.deleteMany();
  await prisma.user.deleteMany();

  // 创建分类
  const categories = await Promise.all([
    prisma.category.create({
      data: {
        name: 'Electronics',
        slug: 'electronics',
      },
    }),
    prisma.category.create({
      data: {
        name: 'Clothing',
        slug: 'clothing',
      },
    }),
    prisma.category.create({
      data: {
        name: 'Home & Garden',
        slug: 'home-garden',
      },
    }),
  ]);

  // 创建用户
  const users = await Promise.all(
    Array.from({ length: 20 }, async () => {
      const firstName = faker.person.firstName();
      const lastName = faker.person.lastName();

      return prisma.user.create({
        data: {
          username: faker.internet.userName({ firstName, lastName }),
          email: faker.internet.email({ firstName, lastName }),
          passwordHash: faker.string.alphanumeric(60), // 实际应用中使用bcrypt
          active: faker.datatype.boolean(0.9), // 90% 活跃
          createdAt: faker.date.past({ years: 2 }),
        },
      });
    })
  );

  console.log(`创建了 ${users.length} 个用户`);

  // 创建产品
  const products = await Promise.all(
    Array.from({ length: 50 }, async () => {
      return prisma.product.create({
        data: {
          name: faker.commerce.productName(),
          description: faker.commerce.productDescription(),
          price: parseFloat(faker.commerce.price({ min: 10, max: 2000 })),
          stockQuantity: faker.number.int({ min: 0, max: 100 }),
          categoryId: faker.helpers.arrayElement(categories).id,
          createdAt: faker.date.past({ years: 1 }),
        },
      });
    })
  );

  console.log(`创建了 ${products.length} 个产品`);

  // 创建带项目的订单
  const activeUsers = users.filter(u => u.active);

  for (let i = 0; i < 100; i++) {
    const user = faker.helpers.arrayElement(activeUsers);
    const orderProducts = faker.helpers.arrayElements(
      products,
      faker.number.int({ min: 1, max: 5 })
    );

    const orderItems = orderProducts.map(product => ({
      productId: product.id,
      quantity: faker.number.int({ min: 1, max: 3 }),
      price: product.price,
    }));

    const totalAmount = orderItems.reduce(
      (sum, item) => sum + item.price * item.quantity,
      0
    );

    await prisma.order.create({
      data: {
        userId: user.id,
        totalAmount,
        status: faker.helpers.arrayElement([
          'pending',
          'processing',
          'completed',
          'cancelled',
        ]),
        createdAt: faker.date.past({ years: 0.5 }),
        items: {
          create: orderItems,
        },
      },
    });
  }

  console.log('创建了100个带项目的订单');

  // 创建评论
  for (let i = 0; i < 150; i++) {
    const user = faker.helpers.arrayElement(activeUsers);
    const product = faker.helpers.arrayElement(products);

    // 检查用户是否已评论此产品
    const existingReview = await prisma.review.findFirst({
      where: {
        userId: user.id,
        productId: product.id,
      },
    });

    if (!existingReview) {
      await prisma.review.create({
        data: {
          userId: user.id,
          productId: product.id,
          rating: faker.number.int({ min: 1, max: 5 }),
          comment: faker.helpers.maybe(() => faker.lorem.paragraph(), { probability: 0.7 }),
          createdAt: faker.date.past({ years: 0.5 }),
        },
      });
    }
  }

  console.log('创建了评论');
  console.log('播种完成!');
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
// package.json
{
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  }
}
# 运行种子
npx prisma db seed

TypeORM 种子生成器

// src/database/seeds/user.seeder.ts
import { DataSource } from 'typeorm';
import { Seeder } from 'typeorm-extension';
import { faker } from '@faker-js/faker';
import { User } from '../entities/user.entity';
import { Order } from '../entities/order.entity';
import { Product } from '../entities/product.entity';

export default class UserSeeder implements Seeder {
  async run(dataSource: DataSource): Promise<void> {
    const userRepository = dataSource.getRepository(User);
    const productRepository = dataSource.getRepository(Product);
    const orderRepository = dataSource.getRepository(Order);

    // 创建用户
    const users: User[] = [];
    for (let i = 0; i < 50; i++) {
      const user = userRepository.create({
        username: faker.internet.userName(),
        email: faker.internet.email(),
        passwordHash: faker.string.alphanumeric(60),
        active: faker.datatype.boolean(0.9),
        createdAt: faker.date.past({ years: 2 }),
      });
      users.push(user);
    }
    await userRepository.save(users);

    console.log(`播种了 ${users.length} 个用户`);

    // 创建产品
    const products: Product[] = [];
    for (let i = 0; i < 100; i++) {
      const product = productRepository.create({
        name: faker.commerce.productName(),
        description: faker.commerce.productDescription(),
        price: parseFloat(faker.commerce.price({ min: 10, max: 1000 })),
        stockQuantity: faker.number.int({ min: 0, max: 100 }),
        createdAt: faker.date.past({ years: 1 }),
      });
      products.push(product);
    }
    await productRepository.save(products);

    console.log(`播种了 ${products.length} 个产品`);

    // 创建订单
    const activeUsers = users.filter(u => u.active);
    const orders: Order[] = [];

    for (let i = 0; i < 200; i++) {
      const user = faker.helpers.arrayElement(activeUsers);
      const orderProducts = faker.helpers.arrayElements(
        products,
        faker.number.int({ min: 1, max: 5 })
      );

      const totalAmount = orderProducts.reduce(
        (sum, p) => sum + p.price * faker.number.int({ min: 1, max: 3 }),
        0
      );

      const order = orderRepository.create({
        user,
        totalAmount,
        status: faker.helpers.arrayElement([
          'pending',
          'processing',
          'completed',
          'cancelled',
        ]),
        createdAt: faker.date.past({ years: 0.5 }),
      });
      orders.push(order);
    }
    await orderRepository.save(orders);

    console.log(`播种了 ${orders.length} 个订单`);
  }
}
# 运行种子生成器
npm run seed

Python 种子生成器

Django Fixtures

# management/commands/seed.py
from django.core.management.base import BaseCommand
from faker import Faker
from app.models import User, Product, Category, Order, OrderItem
import random
from decimal import Decimal

class Command(BaseCommand):
    help = '用示例数据播种数据库'

    def add_arguments(self, parser):
        parser.add_argument(
            '--users',
            type=int,
            default=50,
            help='要创建的用户数'
        )
        parser.add_argument(
            '--products',
            type=int,
            default=100,
            help='要创建的产品数'
        )
        parser.add_argument(
            '--orders',
            type=int,
            default=200,
            help='要创建的订单数'
        )

    def handle(self, *args, **options):
        fake = Faker()

        # 清除现有数据
        self.stdout.write('清除现有数据...')
        OrderItem.objects.all().delete()
        Order.objects.all().delete()
        Product.objects.all().delete()
        Category.objects.all().delete()
        User.objects.all().delete()

        # 创建分类
        self.stdout.write('创建分类...')
        categories = []
        category_names = ['Electronics', 'Clothing', 'Home & Garden', 'Books', 'Sports']
        for name in category_names:
            category = Category.objects.create(
                name=name,
                slug=name.lower().replace(' ', '-')
            )
            categories.append(category)

        # 创建用户
        self.stdout.write(f'创建 {options["users"]} 个用户...')
        users = []
        for _ in range(options['users']):
            user = User.objects.create(
                username=fake.user_name(),
                email=fake.email(),
                password_hash=fake.sha256(),
                active=fake.boolean(chance_of_getting_true=90),
                created_at=fake.date_time_this_year()
            )
            users.append(user)

        # 创建产品
        self.stdout.write(f'创建 {options["products"]} 个产品...')
        products = []
        for _ in range(options['products']):
            product = Product.objects.create(
                name=fake.catch_phrase(),
                description=fake.text(max_nb_chars=200),
                price=Decimal(random.uniform(10, 1000)).quantize(Decimal('0.01')),
                stock_quantity=random.randint(0, 100),
                category=random.choice(categories),
                created_at=fake.date_time_this_year()
            )
            products.append(product)

        # 创建订单
        self.stdout.write(f'创建 {options["orders"]} 个订单...')
        active_users = [u for u in users if u.active]
        statuses = ['pending', 'processing', 'completed', 'cancelled']

        for _ in range(options['orders']):
            user = random.choice(active_users)
            order_products = random.sample(products, random.randint(1, 5))

            order = Order.objects.create(
                user=user,
                status=random.choice(statuses),
                total_amount=0,  # 稍后计算
                created_at=fake.date_time_this_year()
            )

            total = Decimal('0.00')
            for product in order_products:
                quantity = random.randint(1, 3)
                OrderItem.objects.create(
                    order=order,
                    product=product,
                    quantity=quantity,
                    price=product.price
                )
                total += product.price * quantity

            order.total_amount = total
            order.save()

        self.stdout.write(self.style.SUCCESS('成功播种数据库!'))
# 运行种子生成器
python manage.py seed --users 100 --products 200 --orders 500

Factory Boy (Python)

# factories.py
import factory
from factory.django import DjangoModelFactory
from faker import Faker
from app.models import User, Product, Category, Order, OrderItem

fake = Faker()

class CategoryFactory(DjangoModelFactory):
    class Meta:
        model = Category

    name = factory.Faker('word')
    slug = factory.LazyAttribute(lambda obj: obj.name.lower())

class UserFactory(DjangoModelFactory):
    class Meta:
        model = User

    username = factory.Faker('user_name')
    email = factory.Faker('email')
    password_hash = factory.Faker('sha256')
    active = factory.Faker('boolean', chance_of_getting_true=90)
    created_at = factory.Faker('date_time_this_year')

class ProductFactory(DjangoModelFactory):
    class Meta:
        model = Product

    name = factory.Faker('catch_phrase')
    description = factory.Faker('text', max_nb_chars=200)
    price = factory.Faker('pydecimal', left_digits=4, right_digits=2, positive=True, min_value=10, max_value=1000)
    stock_quantity = factory.Faker('random_int', min=0, max=100)
    category = factory.SubFactory(CategoryFactory)
    created_at = factory.Faker('date_time_this_year')

class OrderFactory(DjangoModelFactory):
    class Meta:
        model = Order

    user = factory.SubFactory(UserFactory, active=True)
    status = factory.Faker('random_element', elements=['pending', 'processing', 'completed', 'cancelled'])
    total_amount = factory.Faker('pydecimal', left_digits=5, right_digits=2, positive=True)
    created_at = factory.Faker('date_time_this_year')

class OrderItemFactory(DjangoModelFactory):
    class Meta:
        model = OrderItem

    order = factory.SubFactory(OrderFactory)
    product = factory.SubFactory(ProductFactory)
    quantity = factory.Faker('random_int', min=1, max=5)
    price = factory.LazyAttribute(lambda obj: obj.product.price)

# seed_db.py
from factories import UserFactory, ProductFactory, CategoryFactory, OrderFactory, OrderItemFactory

# 创建数据
categories = CategoryFactory.create_batch(5)
users = UserFactory.create_batch(50)
products = ProductFactory.create_batch(100)
orders = OrderFactory.create_batch(200)

print(f'创建了 {len(users)} 个用户, {len(products)} 个产品, {len(orders)} 个订单')

现实世界数据场景

电子商务平台

// 现实电子商务场景
import { faker } from '@faker-js/faker';

// 创建现实产品目录
const productCategories = {
  electronics: [
    { name: 'MacBook Pro 16"', price: 2499, stock: 15 },
    { name: 'iPhone 15 Pro', price: 999, stock: 50 },
    { name: 'iPad Air', price: 599, stock: 30 },
    { name: 'AirPods Pro', price: 249, stock: 100 },
  ],
  clothing: [
    { name: 'Men\'s T-Shirt', price: 29.99, stock: 200 },
    { name: 'Women\'s Jeans', price: 79.99, stock: 150 },
    { name: 'Sneakers', price: 89.99, stock: 80 },
    { name: 'Winter Jacket', price: 149.99, stock: 60 },
  ],
};

// 创建现实用户画像
const userPersonas = [
  {
    type: 'frequent_buyer',
    orderFrequency: 'high',
    avgOrderValue: 200,
    preferredCategories: ['electronics'],
  },
  {
    type: 'occasional_shopper',
    orderFrequency: 'medium',
    avgOrderValue: 100,
    preferredCategories: ['clothing'],
  },
  {
    type: 'bargain_hunter',
    orderFrequency: 'low',
    avgOrderValue: 50,
    preferredCategories: ['clothing', 'home'],
  },
];

// 创建匹配用户行为的订单
function generateRealisticOrders(user, persona) {
  const orderCount = {
    high: faker.number.int({ min: 10, max: 50 }),
    medium: faker.number.int({ min: 3, max: 10 }),
    low: faker.number.int({ min: 1, max: 3 }),
  }[persona.orderFrequency];

  const orders = [];
  for (let i = 0; i < orderCount; i++) {
    const products = getProductsFromCategories(persona.preferredCategories);
    const total = calculateTotal(products, persona.avgOrderValue);

    orders.push({
      userId: user.id,
      products,
      totalAmount: total,
      status: getRealisticStatus(),
      createdAt: faker.date.past({ years: 1 }),
    });
  }

  return orders;
}

function getRealisticStatus() {
  // 80% 完成, 10% 处理中, 5% 待处理, 5% 取消
  const rand = Math.random();
  if (rand < 0.8) return 'completed';
  if (rand < 0.9) return 'processing';
  if (rand < 0.95) return 'pending';
  return 'cancelled';
}

SaaS 多租户

# 现实SaaS数据
from faker import Faker
import random
from datetime import datetime, timedelta

fake = Faker()

# 组织规模(现实分布)
ORG_SIZES = {
    'startup': {'users': (1, 5), 'projects': (1, 3), 'weight': 0.5},
    'small': {'users': (5, 20), 'projects': (3, 10), 'weight': 0.3},
    'medium': {'users': (20, 100), 'projects': (10, 50), 'weight': 0.15},
    'enterprise': {'users': (100, 500), 'projects': (50, 200), 'weight': 0.05},
}

def create_organization():
    org_type = random.choices(
        list(ORG_SIZES.keys()),
        weights=[v['weight'] for v in ORG_SIZES.values()]
    )[0]

    config = ORG_SIZES[org_type]

    org = Organization.objects.create(
        name=fake.company(),
        slug=fake.slug(),
        plan=org_type,
        created_at=fake.date_time_between(start_date='-2y', end_date='now')
    )

    # 为组织创建用户
    user_count = random.randint(*config['users'])
    users = []
    for i in range(user_count):
        role = 'admin' if i == 0 else random.choice(['member', 'member', 'member', 'viewer'])
        user = User.objects.create(
            organization=org,
            email=fake.email(),
            name=fake.name(),
            role=role,
            created_at=org.created_at + timedelta(days=random.randint(0, 30))
        )
        users.append(user)

    # 创建项目
    project_count = random.randint(*config['projects'])
    for _ in range(project_count):
        Project.objects.create(
            organization=org,
            owner=random.choice(users),
            name=fake.catch_phrase(),
            description=fake.text(),
            status=random.choice(['active', 'active', 'active', 'archived']),
            created_at=org.created_at + timedelta(days=random.randint(0, 60))
        )

    return org

最佳实践

推荐做法 ✓

  • 使用现实世界数据 - 姓名、电子邮件、地址应看起来真实
  • 维持引用完整性 - 尊重外键约束
  • 创建多样场景 - 包括边界情况,而不仅是正常路径
  • 设置随机种子以可重复 - faker.seed(12345)
  • 播种前清除数据 - 防止重复键错误
  • 按正确顺序播种 - 父级在前子级在后
  • 使用事务 - 出错时回滚
  • 添加有意义的关系 - 现实用户-订单模式
  • 包括时间戳 - 分布在实际时间段
  • 验证数据 - 确保生成数据满足约束

避免做法 ✗

  • 不要对所有用户使用相同密码 - 变化或使用faker
  • 不要忽略约束 - 检查NOT NULL、UNIQUE、CHECK
  • 不要创建不现实数据 - 没有200岁的用户
  • 不要硬编码ID - 使用自动生成值
  • 不要在生产环境播种 - 仅限开发/暂存环境
  • 不要创建过多数据 - 从小开始,根据需要增加
  • 不要忽略性能 - 大数据集使用批量插入
  • 不要忘记清理 - 完成后删除测试数据

性能提示

批量插入

// 而不是逐个创建
for (const data of userData) {
  await prisma.user.create({ data });
}

// 使用createMany
await prisma.user.createMany({
  data: userData,
  skipDuplicates: true,
});

多表事务

await prisma.$transaction(async (tx) => {
  const users = await tx.user.createMany({ data: userData });
  const products = await tx.product.createMany({ data: productData });
  const orders = await tx.order.createMany({ data: orderData });
});

注意事项

  • 始终播种开发和暂存环境,绝不要生产环境
  • 使用环境变量控制播种行为
  • 在版本控制中包含种子数据以确保一致性
  • 记录种子场景以利团队理解
  • 考虑使用数据库快照以实现更快的重置
  • 定期用播种数据测试应用程序
  • 保持播种脚本与架构更改同步