xyz.refineryteam.refinerycore.api.database provides persistent SQL storage backed by HikariCP connection pooling, plus a repository layer that generates dialect-correct SQL for whichever backend you choose — so your plugin’s data-access code doesn’t need to branch on database type.
Looking for data that doesn’t need to survive a restart? See Temporary Storage instead — persistent storage in RefineryCore always means this database layer.
Supported databases
Opening a database
RefineryDatabase has one static factory method per supported type:
PluginDatabase.java
sqlite, h2) resolve their file relative to the plugin’s data folder and create parent directories automatically. Networked databases (mysql, mariadb, postgresql) are pre-tuned with reasonable pool sizing, timeouts, and prepared-statement caching.
Always close the database on plugin disable:
Plugin.java
The repository pattern
Rather than writing raw SQL per-entity, extendAbstractRepository<T, ID> and describe your entity’s shape — table creation, upserts, and lookups are generated for you in a dialect-correct way.
Defining an entity and repository
PlayerRepository.java
Registering repositories
RepositoryRegistry tracks repositories against a database, creating each one’s table on registration:
Plugin.java
register() returns the same instance you passed in, so you can assign it directly for convenient access elsewhere in your plugin. Call registry.close() (which closes the underlying database) from onDisable().
Using a repository
EveryRepository<T, ID> exposes standard CRUD, each with a blocking and an async (CompletableFuture-based) variant:
PlayerManager.java
save() is always an upsert — insert if the primary key doesn’t exist, update if it does — using each dialect’s native syntax (ON DUPLICATE KEY UPDATE for MySQL/MariaDB/H2, ON CONFLICT ... DO UPDATE for SQLite/PostgreSQL) so you never need to check existence yourself before saving.
AbstractRepository also exposes findPage(limit, offset) for pagination without hand-writing LIMIT/OFFSET, and a protected withConnection(ConnectionAction) escape hatch for custom queries (joins across repositories sharing a database, complex WHERE clauses) that the standard CRUD surface doesn’t cover.
Dialect handling — SqlDialect
SqlDialect (xyz.refineryteam.refinerycore.api.database.dialect) encapsulates the small syntax differences between backends that AbstractRepository needs to generate correct SQL:
You generally don’t need to touch
SqlDialect directly — AbstractRepository resolves it automatically from the RefineryDatabase’s DatabaseType via SqlDialect.of(type). It’s useful to know it exists if you’re writing custom SQL via withConnection and want dialect-correct quoting/upserts without duplicating branching logic.
Low-level access
For anything the repository layer doesn’t cover,RefineryDatabase still exposes raw SQL helpers:
PlayerManager.java
db.getConnection() returns a raw java.sql.Connection from the pool for anything even lower-level.
Required dependencies
Add the JDBC driver(s) for whichever database(s) you use:libraries.addAll(...) in bukkitPluginYaml (rather than shading them) so Paper’s library loader resolves them at runtime:

