Base de datos
Records guardados en H2, MySQL, MariaDB, PostgreSQL o MongoDB — un pool, sin reflexión por fila, sin bloquear.
Una tabla es un record. No hay DAO, ni SQL en tu plugin, ni configuración de ORM.
@Table("player_stats")
public record PlayerStats(
@Id(length = 36) String uuid,
@Column int kills,
@Column int deaths,
@Column("created_at") long createdAt) {
}Repository<PlayerStats> stats = Databases.of(this).repository(PlayerStats.class);La tabla se crea al primer uso, y un componente nuevo se convierte en una columna nueva.
Anotaciones
| Anotación | Qué hace |
|---|---|
@Table("nombre") | La tabla en la que vive este record. |
@Id(length = …) | La clave primaria. |
@Column | Un componente guardado. @Column("otro_nombre") cuando el nombre de columna difiere. |
@Column(length = Column.UNBOUNDED) | Texto sin límite — TEXT en H2, LONGTEXT en MySQL. |
@Indexed / @Index(…) | Índices, incluidos compuestos y descendentes. |
Leer y escribir
Todo devuelve un CompletableFuture y nada bloquea el servidor:
stats.find(uuid); // Optional<PlayerStats>
stats.findAll();
stats.exists(uuid);
stats.count();
stats.save(record); // insert o update
stats.saveAll(records);
stats.update(record);
stats.insert(record); // claves generadas
stats.insertReturning(record);
stats.delete(uuid);Consultas
stats.where("arenaId", "nodebuff")
.orderByDescending("kills")
.limit(10)
.find();| Llamada | Qué hace |
|---|---|
where(columna, valor) | Filtrar. Encadenable. |
orderBy / orderByDescending | Ordenar. |
limit(filas) / skip(filas) | Paginar. |
find() / findFirst() | Ejecutarla. |
count() / delete() | Contar o borrar lo que coincida. |
La ordenación ocurre en la base de datos, y por eso un leaderboard guarda sus valores derivados en vez de calcularlos al leer: una base de datos no puede ordenar por algo que solo Java sabe deducir.
Motores
Cada plugin recibe su plugins/<Plugin>/database.yml:
database:
type: h2
settings:
max-pool-size: 0
h2:
file: database/h2
auto-server: false
mysql:
host: localhost
port: 3306
database: minecraft
username: root
password: ""h2, mysql, mariadb, postgresql, mongodb. Solo se lee el bloque que coincide con type; un
valor no reconocido cae a h2 y lo dice.
El auto-server de H2 conviene conocerlo: un archivo de H2 pertenece a una JVM, y el segundo proceso
que lo abre recibe "The file is locked". Activarlo hace que el primer servidor sirva el archivo a los
demás por TCP — que es lo que permite compartirlo entre dos plugins de una máquina, o un servidor más
un visor de base de datos. Para cualquier cosa que no esté en una máquina, monta una base de datos de
verdad.
Cero deja decidir al motor, que es lo correcto casi siempre: una base de datos embebida quiere un puñado de conexiones y una en red se dimensiona por los núcleos de la máquina. Súbelo solo si la consola reporta timeouts de conexión — un pool más grande contra una base de datos que ya es el cuello de botella la hace más lenta.
Los plugins cuyos ajustes resueltos coinciden comparten un pool. Dos plugins apuntando al mismo MySQL abren un cliente, no dos.
Tipos que la librería no puede conocer
Un componente cuyo tipo es tuyo necesita un codec, registrado antes del primer
repository(Tipo.class) — un record se compila cuando se crea su repositorio y resuelve sus codecs en
ese momento:
public static void registerCodecs() {
Databases.codec(ArenaBounds.class, ArenaBounds.CODEC);
Databases.codec(ArenaRules.class, Codec.of(
rules -> GSON.toJson(rules),
stored -> GSON.fromJson(stored, ArenaRules.class)));
}Location, ItemStack, ItemStack[] y los enums ya se conocen.
Una columna que creció
La longitud de un campo puede crecer entre dos versiones de un plugin — una columna de icono declarada de 64 caracteres que luego guarda un objeto serializado. La tabla de un servidor que ya existe sigue con el ancho viejo, y el primer valor largo se rechaza, o se trunca en algo que ya no se puede volver a leer.
Una columna de texto más estrecha de lo que declara el record se ensancha en el sitio en el
arranque que lo detecta, y el cambio se nombra en el resumen de esquema. Sus datos y su nombre no se
tocan, y una columna NOT NULL sigue siendo NOT NULL.
Nunca va en el otro sentido: una columna guardada más ancha de lo que declara el record se deja tal cual, porque puede ser la vista de otro plugin sobre la misma tabla y estrecharla trunca filas. Las columnas numéricas no se tocan — la precisión no es un ancho. Una base de datos que rechace la alteración se deja como estaba en vez de impedir el arranque, con un aviso que nombra la tabla y la columna.
Mover datos
/exylialib export <plugin>
/exylialib import <plugin> <archivo> [force]La base de datos entera de un plugin a un archivo y de vuelta: de H2 a MySQL, o a otro servidor. Los
plugins también pueden exponerlo ellos mismos — ExyliaEvents envuelve las mismas llamadas en
/eventsadmin export.
Redis
Opcional, y apagado por defecto. Configurado, hace que una base de datos se vea igual desde cada servidor: un cambio en uno es visible en los otros al momento, en vez de tras expirar una caché.
Un future se completa en un hilo del pool. Todo lo que hagas con la respuesta que toque a un jugador o al mundo tiene que volver antes por el scheduler.
¿Falta algo en esta página? Dínoslo en Discord