Nestjs框架: 由权限模型设计到 Prisma 数据库迁移的演示
好的,接下来我将根据你提供的内容,整理出一个结构清晰、逻辑严谨、信息量大的项目实操指导文档,用于指导你完成 RDAC权限系统中的数据库建模与迁移管理实践,包括:
- 数据库结构补充:角色、用户角色关系建模
- Prisma Migrate 生命周期管理命令详解
- 数据库迁移脚本的创建与管理
- 生产与开发数据库同步策略
- 多迁移版本控制与冲突解决机制
数据库添加User模型
基于Prisma设计User模型
generator client {provider = "prisma-client-js"output = "./clients/postgresql"
}datasource db {provider = "postgresql"url = env("DATABASE_URL")
}model User {id Int @id @default(autoincrement())username String @uniquepassword String// userRole UserRole[] // 后面添加Role模型的时候,要把这个打开@@map("users")
}
以上是一开始的User模型,我们先把这个模型同步到远程,此时远程没有 testdb 数据库
我们现在执行 $ $ npx prisma migrate dev --name init
--name init
:定义本次迁移的名称,便于后续追踪- 执行该命令后,Prisma 会:
- 删除当前数据库(开发环境允许)
- 重新创建数据库结构
- 创建初始的迁移文件(
migration.sql
)
- 若不想确认删除数据,可添加
--force
参数
输出如下
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "testdb", schema "public" at "localhost:15432"PostgreSQL database testdb created at localhost:15432Applying migration `20250813093251_init`The following migration(s) have been created and applied from new schema changes:prisma/migrations/└─ 20250813093251_init/└─ migration.sqlYour database is now in sync with your schema.✔ Generated Prisma Client (v6.12.0) to ./prisma/clients/postgresql in 168ms
查看数据库是否同步
可以看到,数据库同步了,注意,也可以生成迁移脚本但不应用到数据库
npx prisma migrate dev --name role --create-only
- 仅生成 SQL 脚本,不执行数据库操作
- 适用于预览或审查脚本内容后再决定是否执行
下面我们继续补充数据库模型
数据库结构补充:角色模型设计
1 )添加 Role 和 UserRole 模型
model Role {id Int @id @default(autoincrement())name String @unique // 角色名称(如:admin、editor) description String? // 角色描述 createdAt DateTime @default(now())updatedAt DateTime @updatedAtusers UserRole[] // 关联用户(多对多) // permissions RolePermission[] // 关联权限(多对多)这个暂时用不到 @@map("roles")
}model UserRole {userId IntroleId Intuser User @relation(fields: [userId], references: [id], onDelete: Cascade)role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)@@id([userId, roleId]) // 联合主键 @@map("user_roles") // 数据库表名
}
关于 Role
id
:角色的唯一标识符name
:角色名称,唯一性保证description
:角色描述,可选字段users
:与用户角色之间的关系
关于 UserRole
- 联合主键(userId, roleId)用于保证一个用户只能拥有一个角色
- 使用
@@map
指定数据库表名,便于后续维护 - 该模型用于连接用户与角色之间的映射关系
2 ) 解开 User 模型中的注释
model User {userRole UserRole[] // 这里之前的注释打开
}
3 ) 之后,我们继续执行迁移
现在执行 $ $ npx prisma migrate dev --name role
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "testdb", schema "public" at "localhost:15432"Applying migration `20250813101143_role`The following migration(s) have been created and applied from new schema changes:prisma/migrations/└─ 20250813101143_role/└─ migration.sqlYour database is now in sync with your schema.✔ Generated Prisma Client (v6.12.0) to ./prisma/clients/postgresql in 543ms
这时候,我们的 src/prisma/migrations 中有了2次迁移记录
刷新远程数据库,查看已经同步了
4 ) 我们查看总共的迁移记录如下
执行 $ npx prisma migrate status
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "testdb", schema "public" at "localhost:15432"2 migrations found in prisma/migrationsDatabase schema is up to date!
注意,这个命令会
- 查看当前所有未应用的迁移
- 适用于生产环境前的检查
Prisma Migrate 其他管理命令详解
1 ) 应用所有迁移到数据库
npx prisma migrate deploy
- 适用于生产环境部署
- 自动执行所有未应用的迁移
- 自动按时间戳顺序执行 migrations 目录中的所有 SQL
- 若数据库不存在会自动创建
2 ) 数据重置(开发环境专用)
需清空数据库并重新应用所有迁移(生产环境禁止使用):
npx prisma migrate reset
- 作用:删除所有表 → 重新创建数据库 → 应用所有迁移脚本 → 执行 seed 脚本(若有)
- 如果没有数据库,它会自动创建数据库
3 ) 回滚某次迁移
npx prisma migrate resolve --rolled-back "20250813101143_role"
适用场景
- 迁移执行失败后修复:当迁移因语法错误、依赖问题等失败时,可先标记为回滚,修正迁移文件后重新执行 $
npx prisma migrate dev
- 临时调整迁移顺序:在开发环境中需跳过某次迁移直接应用后续版本时,可通过标记回滚实现状态修正
- 该命令仅修改状态标记,不会删除或恢复数据库中的数据/表结构
- 若需实际回滚数据,需手动编写逆向SQL或使用备份恢复。
完整操作示例
- 场景背景: 假设在开发环境中,迁移20250813101143_role因字段类型错误执行失败,需修复后重新应用
- 标记迁移为已回滚
- $
npx prisma migrate resolve --rolled-back "20250813101143_role"
- $
- 修正迁移文件
- 编辑prisma/migrations/20250813101143_role/migration.sql ,修正字段定义错误(如将重复字段名改为user_role)
- 重新应用迁移
- $
npx prisma migrate dev --name fixed_role_migration
- $
- 此时Prisma会基于修正后的文件生成新迁移,并更新状态记录
步骤详解
查看失败信息
执行npx prisma migrate dev时提示错误:
Error: column “role” of relation “users” already exists
4 ) 手动标记某次迁移为“已应用”
npx prisma migrate resolve --applied "20250813101143_role"
- 用于解决迁移冲突问题,尤其是数据库结构已变更但未通过 Prisma 管理的情况
场景一:数据库结构手动变更后与Prisma迁移状态同步
当数据库已通过外部工具(如SQL客户端)手动执行了表结构修改(例如添加字段、创建索引),而Prisma迁移记录未更新时,可使用migrate resolve --applied
命令将对应迁移标记为已应用,避免重复执行迁移或冲突。
- 操作示例:
假设手动为用户表添加了role
字段,且已创建Prisma迁移文件20250813101143_role
(内含添加role
字段的SQL),但数据库变更已通过外部工具完成,无需再次执行迁移:npx prisma migrate resolve --applied "20250813101143_role"
- 效果:
Prisma会将该迁移记录标记为“已应用”,后续执行prisma migrate dev
时不会重复处理此迁移
场景二:迁移冲突后的状态修复
若因分支合并或迁移文件修改导致迁移历史不一致(例如本地迁移与远程数据库状态冲突),可通过手动标记解决冲突。
- 冲突情境:
开发分支A创建了迁移20250813101143_role
并已应用,开发分支B未同步该迁移却直接修改了数据库。合并分支后,Prisma检测到数据库状态与迁移记录不匹配。 - 解决命令:
npx prisma migrate resolve --applied "20250813101143_role"
- 关键说明:
需确保数据库实际结构与迁移文件内容完全一致,否则可能导致数据不一致[1][2]。
场景三:跳过测试或冗余迁移
在测试环境中,若某迁移因重复执行或环境差异无需实际运行(如仅调整字段注释),可手动标记为已应用以跳过执行。
- 示例流程:
- 创建空迁移(仅含描述性变更):
npx prisma migrate dev --name "update_comment" --create-only
- 手动修改数据库后标记迁移为已应用:
npx prisma migrate resolve --applied "20250813152000_update_comment"
- 创建空迁移(仅含描述性变更):
注意事项与风险提示
注意点 | 详细说明 |
---|---|
数据一致性校验 | 标记前务必通过prisma db pull 或数据库客户端确认实际结构与迁移内容一致。 |
备份建议 | 操作前备份数据库,避免误标记导致迁移历史混乱[1]。 |
生产环境谨慎使用 | 生产环境优先通过正常迁移流程同步变更,手动标记仅作为紧急修复手段[3]。 |
通过上述示例可见,prisma migrate resolve --applied
适用于手动对齐数据库状态与迁移记录的场景,但需严格确保操作前的状态一致性,避免引入隐性错误。
5 ) 对比数据库结构差异
npx prisma migrate diff --from-url "mysql://user:pass@localhost:3306/db1" --to-url "mysql://user:pass@remote:3306/db2"
- 可用于:
- 开发数据库与生产数据库的结构对比
- 生成差异 SQL 语句或用于同步
- 非常适合用于 CI/CD 流程中的数据库一致性验证
脚本自动化与 package.json 配置建议
为提升开发效率,建议在 package.json
中添加以下常用命令:
"scripts": {"migrate:dev": "npx prisma migrate dev","migrate:reset": "npx prisma migrate reset","migrate:deploy": "npx prisma migrate deploy","migrate:status": "npx prisma migrate status","db:push": "npx prisma db push","generate": "npx prisma generate"
}
使用示例:
npm run migrate:dev --name role
npm run migrate:reset
npm run migrate:deploy
多版本迁移控制与冲突解决策略
1 ) 多迁移版本控制
- 每次执行
migrate dev
会生成带时间戳的迁移文件 - 所有迁移文件存放于
prisma/migrations
目录中 - 支持选择性应用某些迁移,跳过部分迁移
2 ) 冲突解决流程
-
冲突场景:
- 本地数据库结构与迁移记录不一致
- 某次迁移执行失败,但记录已标记为成功
-
解决方式:
- 使用
resolve
命令手动标记迁移状态。 - 示例:
npx prisma migrate resolve --applied "20250405123456_init"
- 使用
-
注意事项:
- 不建议在生产环境中频繁使用
migrate:reset
- 建议在 CI/CD 中集成
migrate:status
和migrate:deploy
,确保数据库结构一致性
- 不建议在生产环境中频繁使用
总结与建议
功能模块 | 推荐使用命令 | 使用场景说明 |
---|---|---|
初始化迁移 | migrate dev --name init | 首次创建数据库结构 |
新增迁移脚本 | migrate dev --name role | 添加角色模型 |
应用迁移到生产环境 | migrate deploy | 生产环境数据库结构同步 |
数据库结构对比 | migrate diff | 开发与生产数据库结构差异分析 |
手动解决迁移冲突 | migrate resolve --applied xxx | 迁移记录与数据库状态不一致时使用 |
数据库重置(开发) | migrate reset | 开发过程中快速重置数据库 |
官方资源
- Prisma 官方文档:https://www.prisma.io/docs
- Prisma Migrate 指南:https://www.prisma.io/docs/concepts/components/prisma-migrate
- Prisma Schema 指南:https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference