Cursor 把我数据库数据删了

July 3, 2025

1. 事件概述 (Summary)

在一次使用 AI 编码助手 (Cursor Agent) 协助修复前端问题的过程中,AI Agent 执行了一条破坏性的数据库命令 npx prisma db push --force-reset,导致 PostgreSQL 开发数据库中的所有数据被意外清空。由于此前缺乏有效的数据库备份机制,所有历史餐饮记录数据永久丢失,无法恢复。

2. 事件背景 (Background)

meal-tracker 是一个用于记录个人日常餐饮消费和内容的 Web 应用。在开发过程中,我使用 AI Agent 来提高编码效率来解决一些问题。当时,我正专注于实现一个新的 UI 功能,而数据库被认为是稳定且无需改动的。

3. 事件时间线 (Timeline of Events)

  1. 问题描述: 我向 Cursor Agent 描述了一个前端的问题,希望它能帮我修复。
  2. AI Agent 分析: AI Agent 开始分析项目代码,试图理解问题并找出解决方案。
  3. 错误的操作: 在修复问题的过程中,AI Agent 未经明确提示和确认,执行了 npx prisma db push --force-reset && npx prisma generate 命令。
  4. 数据丢失: --force-reset 参数强制重置了数据库,删除了所有表和数据,然后根据最新的 prisma/schema.prisma 文件重新创建了表结构。
  5. 发现问题: 当我刷新应用时,发现所有历史数据都已消失,只剩下空的表结构。
  6. 确认损失: 检查数据库后,确认所有数据均已被清空。由于没有备份,数据无法恢复。

4. 根本原因分析 (Root Cause Analysis)

  • 核心原因:对 AI Agent 的过度信任与权限失控。 我允许了 AI Agent 在没有严格审查和限制的情况下执行终端命令。AI Agent 为了“修复”一个可能与数据库模型不一致相关的问题(或错误地判断了问题根源),选择了最“彻底”但也是最具破坏性的方式来同步数据库状态。
  • prisma db push --force-reset 的误用:
    • prisma db push 用于将 Prisma schema 同步到数据库,它会使数据库模式与你的 schema 保持一致。
    • --force-reset 是一个非常危险的参数,它会先删除整个数据库,然后重新运行 db push。这通常只在开发初期或测试环境中,需要一个干净的数据库时使用。
    • AI Agent 可能在分析中遇到了 schema 与数据库状态不匹配的错误,并简单粗暴地选择了强制重置作为解决方案,而没有评估其带来的灾难性后果。
  • 缺乏备份机制: 这是导致数据无法恢复的直接原因。无论是开发环境还是生产环境,定期的数据库备份都是数据安全的最后一道防线。我的疏忽在于,认为开发数据不重要,从而忽略了备份的必要性。

5. 影响与教训 (Impact & Lessons Learned)

  • 影响: 所有个人餐饮记录数据永久丢失,项目开发历史数据清零。
  • 教训:
    1. AI 不是银弹,谨慎授予权限: AI Agent 是强大的辅助工具,但绝不能盲目信任。对于任何可能修改文件系统、数据库或执行部署的命令,都必须进行人工审查和确认。
    2. 数据无价,备份先行: 无论是开发数据还是生产数据,都具有其价值。必须建立常态化的、自动的备份机制。
    3. 理解工具的每一个参数: 在使用 prisma 或任何其他强大的 CLI 工具时,必须清楚了解每个参数(尤其是像 --force-reset 这样的危险参数)的确切含义和潜在风险。
    4. 最小权限原则: 为 AI 或任何自动化工具提供尽可能小的权限,避免其访问或修改不相关的资源。

6. PostgreSQL 数据库备份最佳实践

为了避免此类悲剧重演,我整理了这份 PostgreSQL 数据库备份的最佳实践指南。

6.1. 备份类型选择

对于大多数 PostgreSQL 用户来说,逻辑备份 (pg_dump) 是最常用且最灵活的选择。

  • 逻辑备份 (pg_dump): 将数据库对象(如表、数据、schema)导出为一系列 SQL 命令或归档文件。
    • 优点: 灵活(可以恢复单个表)、跨版本、跨平台。
    • 缺点: 对于超大型数据库(TB 级别),恢复速度可能较慢。
  • 物理备份: 直接复制构成数据库的数据文件。
    • 优点: 恢复速度快。
    • 缺点: 相对复杂,通常与时间点恢复(PITR)结合使用,对版本和操作系统有严格要求。

对于个人项目和中小型应用,pg_dump 是完全足够且强烈推荐的。

6.2. 使用 pg_dump 进行备份

pg_dump 是 PostgreSQL 自带的命令行工具,功能强大且可靠。

A. 备份单个数据库

这是最常见的备份方式。它会将 meal_tracker 数据库的完整结构和数据保存到一个 .sql 文件中。

pg_dump -U <username> -h <host> -p <port> <database_name> > backup.sql
  • 提示: 你可能需要输入密码。为了自动化,推荐使用 .pgpass 文件或在环境变量 PGPASSWORD 中设置密码(注意安全风险)。

B. 使用自定义格式 (-Fc)

推荐使用自定义归档格式 (-Fc),它提供了更高的灵活性。

pg_dump -U <username> -h <host> -p <port> -Fc <database_name> > backup.dump
  • 优点:
    • 文件经过压缩,体积更小。
    • 可以使用 pg_restore 工具进行并行恢复,速度更快。
    • 可以选择性地恢复特定的表或数据。

6.3. 从备份中恢复

A. 从 SQL 文件恢复

psql -U <username> -h <host> -p <port> -d <database_name> < backup.sql

B. 从自定义格式 (.dump) 文件恢复

使用 pg_restore 工具。

pg_restore -U <username> -h <host> -p <port> -d <database_name> --clean --if-exists backup.dump
  • --clean: 在恢复前删除数据库对象。
  • --if-exists: 在执行 DROP 命令时不报错(如果对象不存在)。

6.4. 自动化备份策略

手动备份是不可靠的,自动化才是王道。

A. 创建备份脚本

创建一个 shell 脚本来执行备份,例如 backup.sh

#!/bin/bash

# 数据库连接信息
DB_USER="jessie"
DB_HOST="localhost"
DB_PORT="5432"
DB_NAME="meal_tracker"

# 备份目录
BACKUP_DIR="/path/to/your/backups"
# 日期格式
DATE=$(date +%Y-%m-%d_%H-%M-%S)
# 备份文件名
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.dump"

# 确保备份目录存在
mkdir -p "$BACKUP_DIR"

# 导出密码 (更安全的方式是使用 .pgpass)
export PGPASSWORD="your_password_here"

# 执行备份
pg_dump -U "$DB_USER" -h "$DB_HOST" -p "$DB_PORT" -Fc "$DB_NAME" > "$BACKUP_FILE"

# 检查备份是否成功
if [ $? -eq 0 ]; then
  echo "✅ 数据库备份成功: $BACKUP_FILE"
else
  echo "❌ 数据库备份失败"
fi

# 清理旧的备份 (例如,只保留最近7天的)
find "$BACKUP_DIR" -type f -name "*.dump" -mtime +7 -delete
echo "🧹 已清理7天前的旧备份"

# 取消密码导出
unset PGPASSWORD

B. 使用 cron 定时执行

使用 cron 作业来每天自动运行此脚本。

  1. 打开 crontab 编辑器: crontab -e

  2. 添加一行来指定任务(例如,每天凌晨 3 点执行):

    0 3 * * * /bin/bash /path/to/your/backup.sh >> /path/to/your/backup.log 2>&1

6.5. 备份存储与验证

  • 异地存储: 永远不要将备份和原始数据放在同一台服务器上。 考虑使用云存储服务,如 Amazon S3, Google Cloud Storage, 或其他任何可靠的存储方案。
  • 定期验证: 定期尝试从备份中恢复数据到一个测试环境,以确保备份文件的完整性和可用性。未经测试的备份等于没有备份。

7. 结论 (Conclusion)

这次数据丢失事件是一个惨痛但宝贵的教训。它暴露了我在开发流程中对数据安全和工具风险评估的忽视。虽然丢失的数据无法挽回,但通过这次复盘,我不仅加深了对 prisma 工具的理解,更重要的是,我将建立起一套完善的、自动化的数据库备份和恢复流程。

希望我的这次经历能给所有开发者,尤其是那些拥抱 AI 编程的同行们敲响警钟:技术是强大的杠杆,但前提是我们必须牢牢握住它的方向盘。