DatabaseAPI

Java CI with Maven Code Factor Latest Release

CentralDatabase-Logo

1. Overview

CentralDatabase is a lightweight, centralized database API for Minecraft plugins.

It abstracts away connection management, simplifies queries, and provides a clean, developer-friendly way to work with databases.

This plugin is supported by Spigot and Paper.

1.1 Features

2. Installation

Add CentralDatabase to your project using one of the following methods:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.devspexx</groupId>
    <artifactId>CentralDatabase</artifactId>
    <version>v1.2.1</version>
</dependency>

2.2 Manual JAR build

If you prefer building the project yourself:

git clone https://github.com/devspexx/CentralDatabase.git
cd CentralDatabase
mvn clean install

This installs the artifact into your local Maven repository. You can then add it as a dependency using the version defined in the project’s pom.xml (e.g. 1.2.1).

2.2.1 Runtime

CentralDatabase must be available at runtime. You can choose one of the following:

πŸ’‘ If you do not shade it, make sure the CentralDatabase plugin is present on the server.

3. API Usage

How do I integrate CentralDatabase into my plugin?

3.1 Initialize the API

You should initialize the API inside your plugin’s onEnable() method.

import dev.spexx.centralDatabase.config.DatabaseConfigLoader;
import dev.spexx.centralDatabase.query.QueryRunner;

public final class MyPlugin extends JavaPlugin {

    private QueryRunner queryRunner;

    @Override
    public void onEnable() {
        // Save the default config first
        saveDefaultConfig();
        
        // Set up the api
        setupCentralDatabase();
    }
    
    public void setupCentralDatabase() {

        // That means the config from this plugin will be used - fromPlugin(this)
        // Usually, you don't want that, so use the config from CentralDatabase plugin instead!
        // --->
        // DatabaseConfigLoader configLoader = DatabaseConfigLoader.fromPlugin(
        //    CentralDatabase.getProvidingPlugin(CentralDatabase.class));

        DatabaseConfigLoader configLoader = DatabaseConfigLoader.fromPlugin(this);

        queryRunner = new QueryRunner(configLoader);
        
        // Order is important! Keep it like that.
        queryRunner.configureHikari();
        queryRunner.initializeHikari();
        queryRunner.initializeThreadPool();
    }
    
    // Always shutdown the query runner in your JavaPlugin class
    @Override
    public void onDisable() {
        if (queryRunner != null) {
            queryRunner.shutdown();
        }
    }

    public QueryRunner getQueryRunner() {
        return queryRunner;
    }
}

πŸ’‘ CentralDatabase does not auto-start anything. You have full control over lifecycle.

3.2 Executing Queries

All queries are executed asynchronously and return a CompletableFuture.

3.2.1 SELECT query

queryRunner.selectAsync(
    "SELECT * FROM players WHERE uuid = ?",
    uuid.toString() // The amount of parameters equals to amount of `?`
).thenAccept(result -> {

    if (result.isSuccess()) {

        Row row = result.firstRow();

        if (row != null) {
            String name = row.asString("username");
            int coins = row.asInt("coins");
        }

    } else {
        getLogger().warning("Query failed: " + result.error());
    }
});

3.2.2 INSERT query

queryRunner.insertAsync(
    "INSERT INTO players (uuid, username) VALUES (?, ?)",
    uuid.toString(), name
).thenAccept(result -> {
    
    if (result.isSuccess()) {
        long id = result.insertId();
    }
});

3.2.3 UPDATE query

queryRunner.updateAsync(
    "UPDATE players SET coins = ? WHERE uuid = ?",
    100,
    uuid.toString()
);

3.2.4 DELETE query

queryRunner.deleteAsync(
    "DELETE FROM players WHERE uuid = ?",
    uuid.toString()
);

3.3 Working with Results

CentralDatabase provides a type-safe result system.

Example:

queryRunner.selectAsync("SELECT * FROM players")
    .thenAccept(result -> {

        if (result.isSuccess()) {

            for (Row row : result.value()) {
                UUID uuid = row.asUUID("uuid");
                String name = row.asString("username");
            }

        } else {

            QueryError error = result.error();
            getLogger().warning("SQL Error: " + error);

        }
});

3.3.1 Result helpers

3.4 Query Result Codes

Every query returns a structured QueryResultCode. These codes allow you to reliably handle database outcomes without parsing exception messages or relying on driver-specific behavior.

πŸ’‘ Result codes are grouped by origin:

3.4.1 Success States

These codes represent successful query execution.

They indicate that the database operation completed correctly, even if no rows were affected or returned.

Code Description
SELECTED Query returned one or more rows
NO_RESULTS Query executed successfully but returned no rows
UPDATED_ZERO_ROWS Update/Delete affected zero rows
INSERTED Insert operation succeeded
UPDATED Update operation succeeded
DELETED Delete operation succeeded
SUCCESS_WITH_WARNING Query succeeded but produced warnings

3.4.2 Client / Developer Errors

These errors are caused by incorrect queries or invalid input.

They usually indicate a mistake in your code, schema usage, or query structure, and should be fixed rather than retried.

Code Description
SYNTAX_ERROR Invalid SQL syntax
MISSING_OBJECT Table/column does not exist
PERMISSION_DENIED Database user lacks required permissions
INVALID_DATA Invalid value for column
NULL_CONSTRAINT_VIOLATION NULL value in NOT NULL column
TYPE_MISMATCH Value type does not match column type

3.4.3 Database / Engine Failures

These errors originate from the database engine or environment.

They may be temporary (e.g. connection issues, deadlocks) and can often be handled with retries or fallback logic.

Code Description
CONNECTION_ERROR Connection failed or lost
TIMEOUT Query exceeded execution timeout
DEADLOCK Query aborted due to deadlock
LOCK_WAIT_TIMEOUT Lock wait exceeded timeout
DUPLICATE_KEY Unique/primary key constraint violation
FOREIGN_KEY_VIOLATION Foreign key constraint violation
DATA_TRUNCATED Data was truncated
TRANSACTION_ROLLBACK Transaction was rolled back

3.4.4 Internal / System States

These codes represent internal or lifecycle-related conditions.

They are not caused by the database itself, but by the state of the CentralDatabase system or underlying driver.

Code Description
DRIVER_ERROR JDBC driver-level failure
EXECUTION_ERROR Unclassified execution error
NOT_INITIALIZED QueryRunner not initialized

3.4.5 Example Usage (states)

queryRunner.insertAsync(...).thenAccept(result -> {

    if (result.isSuccess()) {
        // All good
        return;
    }

    switch (result.code()) {

        case <STATUS CODE> -> { }

        default -> {
            getLogger().warning("Unhandled DB error: " + result.code());
        }
    }
});

3.5 Configuration

CentralDatabase uses a simple config.yml.

# CentralDatabase configuration
# Handles MySQL connection and async query execution.

# MySQL connection
hostname: localhost
port: 3306
username: root
password: myPassword
database: databaseName

# JDBC connection URL.
# Available placeholders: {hostname}, {port}, {database}
jdbc-url: "jdbc:mysql://{hostname}:{port}/{database}?useSSL=false"

# Number of threads executing SQL queries in parallel.
# Increase for busy servers, decrease for small ones.
thread-pool-size: 4

# Advanced settings for database connection pooling.
# Only change these if you know what you are doing.

hikari:

  # Maximum number of open database connections.
  # Small servers: 5–8
  # Large servers: 10–20
  maximum-pool-size: 10

  # Minimum number of idle connections kept ready.
  minimum-idle: 2

  # How long to wait for a connection before failing (ms).
  connection-timeout: 5000

  # How long an unused connection stays in the pool (ms).
  idle-timeout: 120000

  # Maximum lifetime of a connection before replacement (ms).
  # Must be lower than MySQL's wait_timeout.
  max-lifetime: 1800000

  # Detects leaked connections. 0 disables detection.
  # Enable only when debugging.
  leak-detection-threshold: 0

  # Periodic keep-alive ping to prevent connection drops (ms).
  keepalive-time: 300000

πŸ’‘ Placeholders like {hostname} and {database} are resolved automatically.

3.6 Threading Model

All queries run off the main thread.

Uses:

Main Thread β†’ QueryRunner β†’ Worker Threads β†’ Database

Safe for high-performance environments!

4. Contributing

Pull requests are welcome!

If you find a bug or have a feature request, feel free to open an issue.

5. Final Notes

CentralDatabase is built to simplify database access without sacrificing control.

It removes repetitive JDBC boilerplate and gives you a clean, predictable, and performant way to interact with SQL in Minecraft plugins.

If you find it useful, consider ⭐ starring the repository β€” it helps a lot.