Prismas Schatten-Datenbank und Namensunstimmigkeit: Ein Betriebshandbuch
Warum prisma migrate dev darum bittet, die Datenbank zurückzusetzen, wie man eine sichere Schattendatenbank konfiguriert und wie man Prismas Groß-/Kleinschreibung auf Postgres’ snake_case umwandelt.
Zwei Beschwerden tauchen immer wieder auf, wenn Teams Prisma mit PostgreSQL einsetzen: Das Migrationswerkzeug bietet ständig an, die Entwicklungsdatenbank zu löschen, und die von ihm erstellten Tabellen ähneln in keiner Weise den Namen, die ein Postgres-Administrator verwenden würde. Beides sind dokumentierte Verhaltensweisen und kein Zeichen dafür, dass Prisma für die Produktion ungeeignet ist. Diese Anleitung erklärt, was in jedem Fall vor sich geht, und gibt Ihnen eine kurze Reihe von Regeln, mit denen Sie Ihre Daten sowie Ihre Schema-Vorgaben erhalten bleiben.
Warum prisma migrate dev vorschlägt, die Datenbank zurückzusetzen
Das typische Szenario sieht so aus: Jemand führt npx prisma migrate dev aus, der Befehl stoppt mit einem Fehler, der besagt, dass eine Tabelle oder ein Enum „bereits existiert“, und der schnellste Weg, diese Meldung zu beseitigen, scheint prisma migrate reset zu sein. Dieser Befehl löscht alle Tabellen und spielt die gesamte Migrationsgeschichte von vorne ab.
Zweck der Schattendatenbank
Während der Entwicklung verwendet Prisma Migrate eine zweite, temporäre Datenbank namens Schattendatenbank. Ihre einzige Aufgabe ist die Erkennung von Abweichungen. Bei jedem Aufruf von migrate dev erstellt Prisma eine saubere Schattendatenbank, wendet alle Migrationsdateien darauf an, analysiert das resultierende Schema und vergleicht es mit der eigentlichen Entwicklungsdatenbank.
Falls die beiden nicht übereinstimmen, wurde die Entwicklungsdatenbank außerhalb der Migrationshistorie geändert. Häufige Ursachen sind:
- eine
prisma db push, die Tabellen ohne Erstellung einer Migrationsdatei geändert hat - eine manuelle Änderung über einen SQL-Client
- eine Migrationsdatei, die von einem Teamkollegen erstellt wurde, aber nie gespeichert wurde
Prisma kann nicht erkennen, welche Version der Daten Sie beibehalten möchten, weshalb es die einzige sichere automatische Option vorschlägt, die es für eine Entwicklungsdatenbank hat: Sie löschen und neu erstellen, basierend auf den Migrationsdateien.
Der nicht gut dokumentierte Fehlermodus
Was Teams überrascht, ist ein anderes Problem mit ähnlichen Symptomen. Bei verwalteten Postgres-Diensten wie Neon oder Supabase fehlt dem Datenbankbenutzer in Ihrer Verbindungszeichenkette oft die Berechtigung, Datenbanken nach Bedarf zu erstellen oder zu löschen. Dadurch kann Prisma seine temporäre Schattendatenbank nicht erstellen und es tritt ein Berechtigungsfehler auf.
Entwickler interpretieren diesen Fehler oft als „die Migrationsprozesse sind gestört“ und führen aufgrund von Ratschlägen aus Community-Threads den Befehl migrate reset aus, um ihn zu beheben. Das ist gefährlich, denn gerade der Reset-Befehl zerstört zuverlässig Daten, wenn die Verbindungszeichenkette auf eine echte Datenquelle verweist. In öffentlichen GitHub-Diskussionen kommt genau diese Geschichte vor: ein Fehler in einer Schattendatenbank, ein ungeplanter Reset als „Lösung“ und Tabellen, die mitten in einem Projekt verloren gehen.
Regeln, die Migrationsprozesse sicher halten
- Weisen Sie Prisma eine eigene Schattendatenbank zu. Setzen Sie
shadowDatabaseUrlauf eine separate Datenbank, in der Ihre Benutzer frei Tabellen erstellen und löschen können. Weisen Sie diese niemals auf eine Produktivdatenbank oder eine gemeinsam genutzte Staging-Datenbank. Je nach Prisma-Version befindet sich diese Einstellung in der Datenquellenkonfiguration der Schema-Datei oder in der Prisma-Konfigurationsdatei – überprüfen Sie daher die aktuellen Dokumentationen, wo Ihre Version sie erwartet. - Betrachten Sie
migrate resetstets als zerstörerische Aktion. Falls es als erstes Problembehebungsverfahren vorgeschlagen wird, stoppen Sie und prüfen Sie stattdessen Anmeldeinformationen, Berechtigungen sowie Abweichungen. - Bedenken Sie, dass die Produktivumgebung anders ist.
prisma migrate deploywendet nur ausstehende Migrationsvorgänge an. Es erstellt niemals eine Schattendatenbank und bittet auch nie um einen Reset. Das Reset-Verhalten gehört aus Designgründen zum Entwicklungsworkflow.
PascalCase-Modelle gegenüber snake_case-Tabellen
Der zweite Konfliktpunkt betrifft die Benennung. Prismas Schema-Sprache empfiehlt Modellnamen im PascalCase-Format und Feldnamen im camelCase-Format, was mit den gängigen Konventionen in JavaScript und TypeScript übereinstimmt. In der Postgres-Welt wird in der Regel das Gegenteil erwartet: snake_case-Identifikatoren, oft mit Pluralformen für Tabellennamen.
Mit den Standardeinstellungen wird ein Modell namens User mit einem Feld firstName zu einer Tabelle namens User mit einer Spalte namens firstName. Postgres akzeptiert dies, doch Identifikatoren mit gemischten Groß- und Kleinschreibweisen müssen in rohem SQL in Anführungszeichen gesetzt werden, was für DBAs, Berichtstools sowie alle Dienste, die die Datenbank direkt lesen und nicht über Prisma zugreifen, ungewohnt erscheint.
Namen abbilden mit @map und @@map
Prisma löst dieses Problem mit zwei Attributen: @map ändert den Namen einer einzelnen Feldspalte, während @@map den Namen der Tabelle hinter einem Modell ändert. Ihr TypeScript-Code behält user.firstName bei, während die Datenbank users.first_name speichert. Die Zuordnung funktioniert gut, wird aber nicht automatisch angewendet. Sie haben zwei Optionen:
- jedes Feld und jedes Modell manuell annotieren – das ist aufwendig, aber vollständig explizit und leicht zu überprüfen
- die externe CLI-Tool
prisma-case-formatverwenden, die den Großschreibungsmodus von Schema-Dateien in Bulk umschreibt und erneut ausgeführt werden kann, damit neue Felder nicht wieder zu den Standardwerten zurückkehren
Egal, welche Option Sie wählen, entscheiden Sie sich vor der ersten Migration. Das Umbenennen von Tabellen und Spalten später bedeutet, Migrationsdateien schreiben zu müssen, die auf vorhandene Daten zugreifen, und jede raw SQL-Anfrage im Codebase muss entsprechend geändert werden.
Wie Drizzle das gleiche Problem bewältigt
Drizzle, die bekannteste TypeScript-first-Alternative, bietet eine casing-Einstellung, die camelCase-Namen im Code auf snake_case-Namen in der Datenbank für das gesamte Schema abbildet. Dies ist ein seltenes Beispiel, in dem die übliche Situation umgekehrt ist. Prisma wird im Allgemeinen als das abstraktere Werkzeug und Drizzle als das dem SQL nähere beschrieben. Dennoch macht Drizzles code-first-Schema eine globale Großschreibregelung einfach, während Prismas separates Schema-System zum Zeitpunkt der Erstellung einen solchen globalen Option als anhaltenden Funktionswunsch hinterlassen hat.
Kernpunkte
- Ein Reset-Aufruf über
migrate devweist auf Abweichungen oder Probleme mit den Berechtigungen der Schattendatenbank hin, nicht auf beschädigte Migrationsdateien. - Konfigurieren Sie eine explizite, isolierte Schattendatenbank für jeden gehosteten Postgres-Anbieter.
migrate reset als allgemeine Lösung; Produktivumgebungen verlassen sich auf migrate deploy, das nichts zurücksetzen kann.@map und @@map (manuell oder mit prisma-case-format), und nicht danach.Falls Sie Prisma im Vergleich zu Drizzle genauer prüfen möchten, behandelt unser Vergleich von raw SQL, Prisma und Drizzle die damit verbundenen Abwägungen ausführlicher.
Zusätzliche Literatur
- MovieVault Walkthrough: Eine Watchlist-API mit Express 5, Prisma 7 und JWT — Eine zeitgebundene Full-Stack-Übung mit detaillierten Anweisungen sowie dem entsprechenden Backend aus Express, Prisma und JWT, inklusive Kommentaren zu Überprüfungen der Rechteverwaltung, Kaskadenreaktionen und Fehlerbehandlung.
- Einführung in Prisma 7 mit PostgreSQL in einem TypeScript-Node.js-Projekt — Behebung der häufigen Einrichtungsfehler von Prisma 7 in TypeScript, von Problemen mit Zeichenketten oder undefinierten URLs bis hin zu Fehlern bei rootDir, sowie Anbindung von PostgreSQL über den pg-Adapter.