Skip to main content
Represents a simple database wrapper for MySQL, MariaDB, and SQLite connections. Before running queries make sure to call connect() methods. You can also override onConnected() to run your code after the connection has been established.
To use this class you must know the MySQL command syntax.

Connection methods

connect()

Establishes a new database connection.
host
String
required
The database host address
port
int
required
The database port number
database
String
required
The database name
user
String
required
The database username
password
String
required
The database password
table
String
Optional table name (accessible as {table} variable in queries)
autoReconnect
boolean
default:"true"
Whether to automatically reconnect on connection loss
// MySQL connection
database.connect("localhost", 3306, "mydb", "user", "pass");

// With table variable
database.connect("localhost", 3306, "mydb", "user", "pass", "players");

// SQLite connection
database.connect("jdbc:sqlite://database.db");

connect(String url)

Connects to a database using a JDBC URL.
url
String
required
The JDBC connection URL (e.g., jdbc:mysql://host:port/database or jdbc:sqlite://database.db)
user
String
The database username (not required for SQLite)
password
String
The database password (not required for SQLite)
table
String
Optional table name for {table} variable replacement
// MySQL with custom URL
database.connect("jdbc:mysql://localhost:3306/mydb", "user", "pass", "players");

// MariaDB
database.connect("jdbc:mariadb://localhost:3306/mydb", "user", "pass");

onConnected()

Called automatically after the first connection has been established. Override this method to run initialization code.
@Override
protected void onConnected() {
    // Create tables, run migrations, etc.
    createTable(TableCreator.of("players")
        .addAutoIncrement("id", "bigint")
        .addNotNull("uuid", "varchar(36)")
        .addNotNull("name", "varchar(16)")
        .add("data", "longtext")
        .setPrimaryColumn("id"));
}

close()

Closes the database connection.
database.close();

close(ResultSet resultSet)

Closes a result set safely.
resultSet
ResultSet
required
The result set to close
ResultSet rs = database.query("SELECT * FROM players");
try {
    // Process results
} finally {
    database.close(rs);
}

Table creation

createTable(TableCreator creator)

Creates a database table using the builder pattern.
creator
TableCreator
required
The table creator with column definitions
createTable(TableCreator.of("players")
    .addAutoIncrement("id", "bigint")
    .addNotNull("uuid", "varchar(36)")
    .add("name", "varchar(16)")
    .addDefault("balance", "double", "0.0")
    .add("data", "longtext")
    .setPrimaryColumn("id"));

TableCreator methods

Adds a new column.
.add("column_name", "data_type")

Query methods

update(String sql)

Executes an UPDATE, INSERT, or DELETE query.
sql
String
required
The SQL query to execute
This method must be called asynchronously to prevent blocking the server.
Common.runAsync(() -> {
    database.update("UPDATE {table} SET balance = 100 WHERE uuid = '" + uuid + "'");
});

query(String sql)

Executes a SELECT query and returns a ResultSet.
sql
String
required
The SQL query to execute
This method must be called asynchronously.
Common.runAsync(() -> {
    ResultSet rs = database.query("SELECT * FROM {table} WHERE uuid = '" + uuid + "'");
    try {
        if (rs.next()) {
            String name = rs.getString("name");
            // Process data
        }
    } finally {
        database.close(rs);
    }
});

select(String table, String where, ResultReader consumer)

Selects rows from a table with a WHERE clause.
table
String
required
The table name (can use {table} variable)
where
String
The WHERE clause (null for all rows)
consumer
ResultReader
required
Callback to process each row
Common.runAsync(() -> {
    database.select("{table}", "uuid = '" + uuid + "'", resultSet -> {
        String name = resultSet.getString("name");
        int balance = resultSet.getInt("balance");
        // Process data
    });
});

select(String table, Map where, ResultReader consumer)

Selects rows using a map of conditions.
table
String
required
The table name
where
Map
Map of column names to values for WHERE clause
consumer
ResultReader
required
Callback to process each row
Map<String, Object> conditions = new HashMap<>();
conditions.put("name", "Steve");
conditions.put("age", 30);

Common.runAsync(() -> {
    database.select("{table}", conditions, resultSet -> {
        // Process matching rows
    });
});

selectAll(String table, ResultReader consumer)

Selects all rows from a table.
table
String
required
The table name
consumer
ResultReader
required
Callback to process each row
Common.runAsync(() -> {
    database.selectAll("{table}", resultSet -> {
        // Process each row
    });
});

Insert methods

insert(SerializedMap columnsAndValues)

Inserts data into the {table} table.
columnsAndValues
SerializedMap
required
Map of column names to values
Common.runAsync(() -> {
    SerializedMap data = SerializedMap.of(
        "uuid", player.getUniqueId().toString(),
        "name", player.getName(),
        "balance", 100.0
    );
    
    database.insert(data);
});

insert(String table, SerializedMap columnsAndValues)

Inserts data into a specific table.
table
String
required
The table name
columnsAndValues
SerializedMap
required
Map of column names to values
On MySQL/MariaDB, this uses INSERT ... ON DUPLICATE KEY UPDATE to update existing rows.
database.insert("players", SerializedMap.of(
    "uuid", uuid.toString(),
    "name", name
));

insertBatch(List maps)

Inserts multiple rows in a single batch operation.
maps
List
required
List of column-value maps to insert
List<SerializedMap> batch = new ArrayList<>();

for (Player player : Bukkit.getOnlinePlayers()) {
    batch.add(SerializedMap.of(
        "uuid", player.getUniqueId().toString(),
        "name", player.getName()
    ));
}

Common.runAsync(() -> database.insertBatch(batch));

Utility methods

count(String table, Object… conditions)

Counts rows matching the given conditions.
table
String
required
The table name
conditions
Object...
required
Key-value pairs for WHERE conditions
Common.runAsync(() -> {
    int count = database.count("{table}", "status", "ACTIVE");
    Common.log("Active players: " + count);
});

addVariable(String name, String value)

Adds a variable that can be used in queries with {name} syntax.
name
String
required
The variable name (without braces)
value
String
required
The value to replace the variable with
public MyDatabase() {
    addVariable("table", "my_custom_table");
    addVariable("prefix", "myprefix_");
}

// In queries:
update("INSERT INTO {prefix}{table} ...");

prepareStatement(String sql)

Creates a prepared statement for parameterized queries.
sql
String
required
The SQL query with ? placeholders
Common.runAsync(() -> {
    try (PreparedStatement ps = database.prepareStatement(
            "SELECT * FROM {table} WHERE uuid = ?")) {
        ps.setString(1, uuid.toString());
        ResultSet rs = ps.executeQuery();
        // Process results
    } catch (SQLException e) {
        e.printStackTrace();
    }
});

isConnected()

Checks if the connection is established and valid.
if (database.isConnected()) {
    // Execute queries
}

isLoaded()

Checks if the connect() method was called.
if (!database.isLoaded()) {
    database.connect(...);
}

isSQLite()

Checks if the connection is to a SQLite database.
if (database.isSQLite()) {
    // SQLite-specific logic
} else {
    // MySQL/MariaDB logic
}

Configuration

setConnectUsingHikari(boolean value)

Enables or disables HikariCP connection pooling (default: enabled).
value
boolean
required
True to use HikariCP, false for standard connections
SimpleDatabase.setConnectUsingHikari(true);
HikariCP requires Minecraft 1.16+ and the com.zaxxer:HikariCP library in your plugin.yml.

Complete example

public class PlayerDatabase extends SimpleDatabase {
    
    public PlayerDatabase() {
        addVariable("table", "players");
    }
    
    public void connect(DatabaseSettings settings) {
        connect(
            settings.getHost(),
            settings.getPort(),
            settings.getDatabase(),
            settings.getUser(),
            settings.getPassword(),
            "players"
        );
    }
    
    @Override
    protected void onConnected() {
        createTable(TableCreator.of("{table}")
            .addAutoIncrement("id", "bigint")
            .addNotNull("uuid", "varchar(36)")
            .addNotNull("name", "varchar(16)")
            .add("balance", "double")
            .add("last_login", "bigint")
            .setPrimaryColumn("id"));
    }
    
    public void savePlayer(Player player, double balance) {
        Common.runAsync(() -> {
            SerializedMap data = SerializedMap.of(
                "uuid", player.getUniqueId().toString(),
                "name", player.getName(),
                "balance", balance,
                "last_login", System.currentTimeMillis()
            );
            
            insert("{table}", data);
        });
    }
    
    public void loadPlayer(UUID uuid, Consumer<PlayerData> callback) {
        Common.runAsync(() -> {
            select("{table}", "uuid = '" + uuid + "'", resultSet -> {
                String name = resultSet.getString("name");
                double balance = resultSet.getDouble("balance");
                long lastLogin = resultSet.getLong("last_login");
                
                PlayerData data = new PlayerData(name, balance, lastLogin);
                
                Common.runLater(() -> callback.accept(data));
            });
        });
    }
}

Build docs developers (and LLMs) love