---
title: "Datenbank & Migrationen"
description: "Multitreibwerkzeug-Datenbankadapter, schemagesteuerter Modellgenerierung und nummerierte SQL-Migrationen."
---

Nibiru bietet fünf Datenbanktreiber hinter einem einheitlichen `Db` Adapter an und einen nummerierten SQL-Migration Runner, der durch die [CLI](/cli/migrations/) getrieben wird.

## Treiberauswahl

Legen Sie den aktiven Treiber in `[DATABASE] driver` Ihrer INI-Datei fest:

| Treiber | Backend | Anmerkungen |
|---|---|---|
| `mysql` | Native MySQL/MariaDB (`mysqli`) | Schnellste, kein PDO-Overhead. |
| `pdo` | PDO MySQL | Empfohlene Standardeinstellung. Vorbereitete Anweisungen, Treiber werden weit verbreitet verwendet. |
| `postgres` | PostgreSQL über **ODBC** | Wenn Ihr Server nur ODBC zur Verfügung hat. |
| `psql` | PostgreSQL über libpq (`pg_*`) | Native PostgreSQL. |
| `postgresql` | Ein Wrapper, der den besten PostgreSQL-Transport zur Laufzeit auswählt. | |
```ini
[DATABASE]
driver   = "pdo"
hostname = "localhost"
port     = 3306
username = "nibiru"
password = "secret"
basename = "nibiru_dev"
encoding = "utf8mb4"
is.active = true
```
Der Dispatcher initialisiert den Treiber beim Booten. Das Wechseln der Treiber erfordert nur eine Änderung der Konfiguration und einen Neustart.

## Der Db Adapter

Jedes generierte Modell erweitert einen treiberspezifischen `Db`-Adapter (`Adapter\MySQL\Db`, `Adapter\PostgreSQL\Db`, `Adapter\Odbc\Db`). Alle Adapter teilen die gleiche Oberfläche:
```php
use Nibiru\Pdo;

// Read a single row by primary-key columns
$row = Pdo::fetchRowInArrayById('users', ['user_id' => 42]);

// Run a parameterised query
$rows = Pdo::fetchAll(
    'SELECT * FROM products WHERE category = :cat',
    [':cat' => 'gold-plating']
);

// Insert
Pdo::insert('products', [
    'name' => 'Marduk Gold Plating',
    'price' => 99.0,
]);

// Update
Pdo::update('products',
    ['price' => 89.0],
    ['id' => 1]);

// Delete
Pdo::delete('products', ['id' => 1]);

// Last insert id
Pdo::lastInsertId();
```
Treiber-spezifische Hilfsmethoden existieren direkt in den Adapter-Klassen selbst (`\Nibiru\Mysql::query()`, `\Nibiru\Postgresql::pgQuery()`, …), wenn Sie unverarbeitten Zugriff benötigen.

## Schema-first Modelle

Wenn `[GENERATOR] database = true` ist, regeneriert der Dispatcher bei jedem Anfrage eine PHP-Klasse pro Tabelle. Siehe [Modelle](/core/models/).

Im Produktionsumfeld:
```ini
[GENERATOR]
database          = false
database.overwrite = false
```
Erneut generieren Sie nur beim Migrieren des Schemas.

## Migrationen

Migrationen sind **reine SQL-Dateien** im Verzeichnis `application/settings/config/database/`, nummeriert für die Ausführungsreihenfolge:
```
application/settings/config/database/
├── 001-acl.sql
├── 002-account.sql
├── 003-api_registry.sql
├── 004-timeanddate.sql
├── 005-user.sql
├── 006-user_to_account.sql
├── 011-acl-data.sql
├── 012-add-unique-key-user.sql
└── 013-add-account-email.sql
```
Die Befehlszeilenschnittstelle wendet sie an mit:
```bash
./nibiru -mi local
APPLICATION_ENV=staging   ./nibiru -mi staging
APPLICATION_ENV=production ./nibiru -mi production
```
Der Runner erstellt eine `_migrations`-Tabelle (pro-Treibername) und überspringt bereits angewendete Dateien. Jede Datei wird als einzelner Batch ausgeführt; wenn ein Anweisungsfehler währenddessen auftritt, beheben Sie den SQL-Fehler und führen erneut aus.

### Dateinamenskonventionen

- Drei-stelliger vorangestellter Nullen-padder numerischer Präfix: `NNN-<slug>.sql`.
- Slugs beschreiben die Änderung (`-add-account-email`, `-drop-wrong-constraints`).
- Eine logische Änderung pro Datei. Verwenden Sie keine Squash-Ausdrücke.
- Für Daten-seeds verwenden Sie den `-data.sql` Suffix (`011-acl-data.sql`).

### Idempotenz

Verwenden Sie `IF NOT EXISTS` und `IF EXISTS`, damit Dateien sicher erneut ausgeführt werden können:
```sql
CREATE TABLE IF NOT EXISTS api_registry (
    api_registry_id     INT(11) NOT NULL AUTO_INCREMENT,
    api_registry_name   VARCHAR(255) NOT NULL,
    api_registry_token  VARCHAR(64)  NOT NULL,
    PRIMARY KEY (api_registry_id),
    UNIQUE KEY api_registry_token_uk (api_registry_token)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
``````sql
ALTER TABLE user
    ADD UNIQUE KEY user_login_uk (user_login)
    /* skip if exists; on MySQL 8 you can wrap with IF NOT EXISTS */;
```
### Zurücksetzungsbefehle (mit Vorsicht verwenden)
```bash
./nibiru -mi-reset local                    # forget all applied migrations
./nibiru -mi-reset-file 005-user.sql local  # forget a single file's run record
```
Diese Befehle entfernen keine Tabellen – nur die `_migrations` Überwachungstabelle. Kombinieren Sie dies mit einer manuellen `DROP`, wenn Sie wirklich eine saubere Sache haben möchten.

## PostgreSQL-Spezifika

Wenn `driver = "psql"` oder `"postgresql"`:

- Verwenden Sie `SERIAL` / `BIGSERIAL` anstelle von `AUTO_INCREMENT`.
- Tabellen in `information_schema.tables` anstelle von `SHOW TABLES`.
- Anführungszeichen: Bezeichner sind doppelt angegeben (`"user"` ist die korrekte Form, da `user` ein reserviertes Wort ist).
- Das bedingte-Kompilierungsflag in der CLI bedeutet, dass PostgreSQL-Builds sich elegant degradiert, wenn `libpq` nicht zur Kompilierzeit vorhanden ist — überprüfen Sie `./nibiru -v`, um die Unterstützung zu bestätigen.

## Verbindungs-Pooling

Es gibt keine eingebaute Pool-Funktion. Für hochverkehrte Anwendungen verwenden Sie:

- **MariaDB / MySQL:** ProxySQL oder HAProxy vor der Datenbank.
- **PostgreSQL:** PgBouncer im Transaktionspooling-Modus.

Nibiru öffnet eine Verbindung pro Anfrage, daher reicht in der Regel ein Pooler aus.

## Häufige Fallen

- **`is.active = false`** deaktiviert die Verbindungen stumm — überprüfen Sie dies, wenn Abfragen `null` zurückgeben.
- **Generator im Produktionsmodus aktiviert.** Mit `[GENERATOR] database = true` wird bei jedem Anfrage die Modelldateien neu geschrieben. Deaktivieren Sie es nach Bereitstellungen.
- **Gemischte Treiber.** Die Auswahl von `mysql` beim Ausführen von PostgreSQL führt zu einem erfolgreichen `Pdo::fetchAll`, das `[]` zurückgibt — die Verbindung schlägt stumm fehl. Überprüfen Sie immer mit `SELECT 1` in einer Rauchtest.
