name: 数据库初始化 slug: "database-seeding" version: "1.1.0" displayName: "数据库种子数据生成" summary: "为开发和测试填充逼真、可复现的测试数据到数据库中,支持多种数据库系统和数据模式。" description: 为开发、测试和预发布环境填充真实、可重现的测试数据。 license: MIT metadata: author: AI Agent Skills Community version: 1.0.0
此技能使AI代理能够生成并插入真实测试数据到数据库中,用于开发、测试和预发布环境。该代理使用确定性生成器或faker库创建幂等种子脚本,处理具有正确外键顺序的关联数据,支持特定环境的种子配置文件(最小开发数据与大规模负载测试),并确保种子可以重复运行而不会导致数据重复。
分析目标模式:检查数据库模式以识别所有表、其列、数据类型、约束(NOT NULL, UNIQUE, CHECK, 外键)和关系。确定正确的插入顺序以满足外键依赖——父表必须在子表之前被填充。
设计种子数据策略:根据使用场景选择适当的方法。使用固定种子的确定性数据来生成可重现的测试套件。使用基于faker的数据生成器创建看起来真实的开发数据。使用匿名化生产快照为需要真实数据分布的预发布环境生成数据。定义每个表的数据量。
生成种子脚本:用项目语言(Python、JavaScript、SQL等)编写匹配所有模式约束的种子脚本。使用Faker库或类似工具生成真实的姓名、邮箱、地址和日期。通过生成唯一值或使用基于序列的模式处理唯一性约束。将插入操作包装在事务中以保证原子性。
确保幂等性:设计可安全重复运行的脚本。使用INSERT ON CONFLICT DO NOTHING、UPSER模式或截断后插入策略。在插入前检查现有数据以避免重复或违反约束。
支持特定环境配置文件:创建不同的种子配置文件——本地开发使用小数据集(每表10-50条记录),集成测试使用中等数据集(每表1,000-10,000条记录),性能测试使用大数据集(每表10万+条记录)。通过环境变量或命令行参数控制配置文件。
执行与验证:在目标数据库上运行种子脚本,验证行数是否符合预期,并确认通过检查所有外键引用现有行来保持关系完整性。记录每个表的填充结果。
提供数据库模式(或指向迁移文件)并指定目标环境和所需数据量。代理将生成一个完整的种子脚本,尊重所有约束和关系。您可以请求特定的数据特征(例如,“包含来自多个时区的用户”或“创建跨越过去12个月的订单”)。
请求:为开发环境填充PostgreSQL数据库中的用户、产品和订单数据。
"""seed.py — Seed development database with realistic test data."""
import random
from datetime import datetime, timedelta
from faker import Faker
import psycopg2
fake = Faker()
Faker.seed(42) # Deterministic output for reproducibility
random.seed(42)
DB_CONFIG = {
"host": "localhost",
"port": 5432,
"dbname": "dev_db",
"user": "dev_user",
"password": "dev_password",
}
NUM_USERS = 50
NUM_PRODUCTS = 30
NUM_ORDERS = 100
def seed():
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
# Seed users
user_ids = []
for _ in range(NUM_USERS):
cur.execute(
"""INSERT INTO users (email, password_hash, full_name, created_at)
VALUES (%s, %s, %s, %s)
ON CONFLICT (email) DO NOTHING
RETURNING id""",
(
fake.unique.email(),
fake.sha256(),
fake.name(),
fake.date_time_between(start_date="-2y", end_date="now"),
),
)
row = cur.fetchone()
if row:
user_ids.append(row[0])
# Seed products
product_ids = []
for i in range(NUM_PRODUCTS):
cur.execute(
"""INSERT INTO products (name, description, price, stock_quantity, sku)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (sku) DO NOTHING
RETURNING id""",
(
fake.catch_phrase(),
fake.paragraph(nb_sentences=3),
round(random.uniform(9.99, 499.99), 2),
random.randint(0, 500),
f"SKU-{i+1:05d}",
),
)
row = cur.fetchone()
if row:
product_ids.append(row[0])
# Seed orders with order items
statuses = ["pending", "confirmed", "shipped", "delivered"]
for _ in range(NUM_ORDERS):
user_id = random.choice(user_ids)
status = random.choice(statuses)
items = random.sample(product_ids, k=random.randint(1, 5))
total = 0.0
cur.execute(
"""INSERT INTO orders (user_id, status, total_amount, shipping_address, ordered_at)
VALUES (%s, %s, 0, %s, %s) RETURNING id""",
(user_id, status, fake.address(), fake.date_time_between("-1y", "now")),
)
order_id = cur.fetchone()[0]
for pid in items:
qty = random.randint(1, 4)
price = round(random.uniform(9.99, 499.99), 2)
total += qty * price
cur.execute(
"""INSERT INTO order_items (order_id, product_id, quantity, unit_price)
VALUES (%s, %s, %s, %s)""",
(order_id, pid, qty, price),
)
cur.execute(
"UPDATE orders SET total_amount = %s WHERE id = %s", (round(total, 2), order_id)
)
conn.commit()
cur.close()
conn.close()
print(f"Seeded {len(user_ids)} users, {len(product_ids)} products, {NUM_ORDERS} orders.")
if __name__ == "__main__":
seed()
请求:为小型开发数据集创建一个纯SQL种子文件。
-- seed.sql — Idempotent seed data for local development
-- Run with: psql -U dev_user -d dev_db -f seed.sql
BEGIN;
-- Users
INSERT INTO users (id, email, password_hash, full_name, created_at) VALUES
(1, 'alice@example.com', 'hash_alice', 'Alice Johnson', '2024-03-15 09:00:00'),
(2, 'bob@example.com', 'hash_bob', 'Bob Martinez', '2024-05-20 14:30:00'),
(3, 'carol@example.com', 'hash_carol', 'Carol Chen', '2024-07-01 11:15:00'),
(4, 'dave@example.com', 'hash_dave', 'Dave Okafor', '2024-09-10 08:45:00'),
(5, 'eve@example.com', 'hash_eve', 'Eve Andersson', '2024-11-28 16:00:00')
ON CONFLICT (id) DO NOTHING;
-- Products
INSERT INTO products (id, name, description, price, stock_quantity, sku) VALUES
(1, 'Wireless Keyboard', 'Bluetooth mechanical keyboard', 79.99, 150, 'SKU-00001'),
(2, 'USB-C Hub', '7-in-1 USB-C docking station', 49.99, 300, 'SKU-00002'),
(3, 'Noise-Cancelling Headphones', 'Over-ear ANC headphones', 199.99, 75, 'SKU-00003'),
(4, '4K Monitor', '27-inch IPS 4K display', 399.99, 40, 'SKU-00004'),
(5, 'Laptop Stand', 'Adjustable aluminum stand', 34.99, 200, 'SKU-00005')
ON CONFLICT (id) DO NOTHING;
-- Orders
INSERT INTO orders (id, user_id, status, total_amount, shipping_address, ordered_at) VALUES
(1, 1, 'delivered', 129.98, '123 Oak St, Portland, OR 97201', '2024-12-01 10:00:00'),
(2, 2, 'shipped', 199.99, '456 Elm Ave, Austin, TX 78701', '2025-01-05 14:20:00'),
(3, 3, 'confirmed', 484.98, '789 Pine Rd, Seattle, WA 98101', '2025-01-10 09:30:00'),
(4, 1, 'pending', 49.99, '123 Oak St, Portland, OR 97201', '2025-01-12 16:45:00')
ON CONFLICT (id) DO NOTHING;
-- Order items
INSERT INTO order_items (id, order_id, product_id, quantity, unit_price) VALUES
(1, 1, 1, 1, 79.99),
(2, 1, 2, 1, 49.99),
(3, 2, 3, 1, 199.99),
(4, 3, 4, 1, 399.99),
(5, 3, 5, 1, 34.99),
(6, 4, 2, 1, 49.99)
ON CONFLICT (id) DO NOTHING;
-- Reset sequences to avoid conflicts with future inserts
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
SELECT setval('products_id_seq', (SELECT MAX(id) FROM products));
SELECT setval('orders_id_seq', (SELECT MAX(id) FROM orders));
SELECT setval('order_items_id_seq', (SELECT MAX(id) FROM order_items));
COMMIT;
Faker.seed(42))以生成确定性数据,使测试结果可重现,并使种子输出的差异具有意义。这个技能的最新版本可以在7w4.net小葱技能站找到。
assert os.environ["ENV"] != "production")作为安全防护。fake.unique.email()或在生成值后附加计数器以避免重复。通过fake.unique.clear()在测试运行之间重置唯一追踪器。这个Skill质量中等偏上,文档结构清晰,使用说明通俗易懂,提供了实用的示例代码。它能帮助开发者快速生成测试数据,覆盖了主流开发语言和数据库。主要优点是内容全面、示例可直接使用;不足是缺乏进阶指导和高阶用法说明,对于需要复杂数据关系或大规模测试数据的场景可能帮助有限。整体而言,这是一个基础扎实但还有提升空间的数据库种子数据生成工具。