---
title: "Base de datos y migraciones"
description: "Adaptador de base de datos multi-controlador, generación de modelos basada en el esquema y migraciones SQL numeradas."
---

Nibiru viene con **cinco controladores de base de datos** detrás de un adaptador unificado `Db`, además de un ejecutor de migraciones numeradas impulsado por la [CLI](/cli/migrations/).

## Elección del controlador

Establece el controlador activo en `[DATABASE] driver` de tu INI:

| Conductor | Backend | Notas |
|---|---|---|
| `mysql` | MySQL/MariaDB nativo (`mysqli`) | Más rápido, sin sobrecarga de PDO. |
| `pdo` | PDO MySQL | Predeterminado recomendado. Sentencias preparadas, los controladores son ampliamente utilizados. |
| `postgres` | PostgreSQL a través de **ODBC** | Cuando solo tiene ODBC disponible en su servidor. |
| `psql` | PostgreSQL a través de libpq (`pg_*`) | PostgreSQL nativo. |
| `postgresql` | Un contenedor que elige el mejor transporte PostgreSQL en tiempo de ejecución. | |
```ini
[DATABASE]
driver   = "pdo"
hostname = "localhost"
port     = 3306
username = "nibiru"
password = "secret"
basename = "nibiru_dev"
encoding = "utf8mb4"
is.active = true
```
El despachador inicializa el controlador durante el arranque. Cambiar de controlador requiere solo un cambio en la configuración y un reinicio.

## El adaptador Db

Cada modelo generado extiende un adaptador específico de `Db` (`Adapter\MySQL\Db`, `Adapter\PostgreSQL\Db`, `Adapter\Odbc\Db`). Todos los adaptadores comparten la misma superficie de área:
```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();
```
Los ayudantes específicos del controlador existen en las propias clases de adaptador (`\Nibiru\Mysql::query()`, `\Nibiru\Postgresql::pgQuery()`, …) cuando necesitas acceso directo.

## Modelos basados en el esquema

Cuando `[GENERADOR] base_de_datos = verdadero`, el despachador regenera una clase PHP por tabla en cada solicitud. Consulte [Modelos](/core/models/).

En producción:
```ini
[GENERATOR]
database          = false
database.overwrite = false
```
Regenera solo cuando migres el esquema.

## Migraciones

Las migraciones son **archivos SQL planos** en `application/settings/config/database/`, numerados para el orden de ejecución:
```
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
```
La CLI los aplica con:
```bash
./nibiru -mi local
APPLICATION_ENV=staging   ./nibiru -mi staging
APPLICATION_ENV=production ./nibiru -mi production
```
El ejecutor crea una tabla `_migrations` (por nombre de controlador) y omite los archivos ya aplicados. Cada archivo se ejecuta como un solo lote; si una declaración falla en medio del proceso, corrige el SQL y vuelve a ejecutar.

### Convenciones de nombramiento de archivos

- Prefijo numérico de tres dígitos rellenado con ceros: `NNN-<slug>.sql`.
- Los slugs describen el cambio (`-add-account-email`, `-drop-wrong-constraints`).
- Un cambio lógico por archivo. No aplastes.
- Para semillas solo de datos, usa el sufijo `-data.sql` (`011-acl-data.sql`).

### Idempotencia

Utiliza `IF NOT EXISTS` y `IF EXISTS` para que los archivos se puedan volver a ejecutar de manera segura:
```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 */;
```
### Comandos de reinicio (usar con cuidado)
```bash
./nibiru -mi-reset local                    # forget all applied migrations
./nibiru -mi-reset-file 005-user.sql local  # forget a single file's run record
```
Estos no eliminan tablas — solo la tabla de auditoría `_migrations`. Combínalos con un `DROP` manual si realmente quieres empezar desde cero.

## Específicos de PostgreSQL

Cuando `driver = "psql"` o `"postgresql"`:

- Utiliza `SERIAL` / `BIGSERIAL` en lugar de `AUTO_INCREMENT`.
- Las tablas en `information_schema.tables` en lugar de `SHOW TABLES`.
- Citas: los identificadores están entre comillas dobles (`"user"` es el formulario correcto porque `user` está reservado).
- La bandera de compilación condicional en la CLI significa que las construcciones de PostgreSQL se degradan graciosamente si libpq no está presente al momento de la compilación — verifica `./nibiru -v` para confirmar el soporte.

## Pooling de conexiones

No hay un pool integrado. Para aplicaciones de alta tráfico utilice:

- **MariaDB / MySQL:** ProxySQL o HAProxy frente a la base de datos.
- **PostgreSQL:** PgBouncer en modo de pooling de transacciones.

Nibiru abre una conexión por solicitud, por lo que un pooler suele ser todo lo que necesitas.

## Trampas comunes

- **`is.active = false`** desactiva silenciosamente las conexiones — verifica esto cuando las consultas devuelvan `null`.
- **Generador activo en producción.** Con `[GENERATOR] database = true`, cada solicitud reescribe tus archivos de modelo. Apágalo después de los despliegues.
- **Controladores mixtos.** Seleccionar `mysql` al ejecutar PostgreSQL te da un `Pdo::fetchAll` exitoso que devuelve `[]` — la conexión falla silenciosamente. Siempre confirma con `SELECT 1` en una prueba de humo.
