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.
The database host address
Optional table name (accessible as {table} variable in queries)
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.
The JDBC connection URL (e.g., jdbc:mysql://host:port/database or jdbc:sqlite://database.db)
The database username (not required for SQLite)
The database password (not required for SQLite)
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.
close(ResultSet resultSet)
Closes a result set safely.
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.
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
add()
addNotNull()
addAutoIncrement()
addDefault()
setPrimaryColumn()
Adds a new column..add("column_name", "data_type")
Adds a NOT NULL column..addNotNull("uuid", "varchar(36)")
Adds an auto-incrementing column..addAutoIncrement("id", "bigint")
Adds a column with a default value..addDefault("status", "varchar(20)", "ACTIVE")
Sets the primary key column.
Query methods
update(String sql)
Executes an UPDATE, INSERT, or DELETE query.
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.
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.
The table name (can use {table} variable)
The WHERE clause (null for all rows)
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.
Map of column names to values for WHERE clause
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.
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.
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.
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.
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.
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.
The variable name (without braces)
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.
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).
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));
});
});
}
}