dev.oum.oumlib.database · Paper / Velocity
Database db = Database.sqlite(new File(getDataFolder(), "data.db"));Database db = Database.mysql("localhost", 3306, "mydb", "user", "password");Both use HikariCP connection pooling under the hood.
All queries are async by default and return a CompletableFuture.
db.executeUpdate("CREATE TABLE IF NOT EXISTS players (uuid TEXT PRIMARY KEY, name TEXT, coins INT)");
db.executeUpdate("INSERT INTO players (uuid, name, coins) VALUES (?, ?, ?)",
player.getUniqueId().toString(), player.getName(), 500);
db.executeUpdate("UPDATE players SET coins = coins + ? WHERE uuid = ?",
100, player.getUniqueId().toString());db.executeQuery("SELECT * FROM players WHERE uuid = ?", uuid.toString())
.thenAcceptSync(rows -> {
if (!rows.isEmpty()) {
Map<String, Object> row = rows.getFirst();
int coins = (int) row.get("coins");
String name = (String) row.get("name");
player.sendMessage("You have " + coins + " coins");
}
});Each row is a Map<String, Object>. Column names are the keys.
.thenAcceptSync() runs the callback on the main thread — safe for Bukkit API calls:
db.executeQuery("SELECT coins FROM players WHERE uuid = ?", uuid.toString())
.thenAcceptSync(rows -> {
// this runs on the main thread
player.teleport(spawn);
});db.transaction(connection -> {
try (var stmt = connection.prepareStatement("UPDATE players SET coins = coins - ? WHERE uuid = ?")) {
stmt.setInt(1, 100);
stmt.setString(2, buyerUuid);
stmt.executeUpdate();
}
try (var stmt = connection.prepareStatement("UPDATE players SET coins = coins + ? WHERE uuid = ?")) {
stmt.setInt(1, 100);
stmt.setString(2, sellerUuid);
stmt.executeUpdate();
}
});If anything throws, the transaction rolls back.
db.executeBatch("INSERT INTO players (uuid, name, coins) VALUES (?, ?, ?)", batch -> {
for (Player p : Bukkit.getOnlinePlayers()) {
batch.add(p.getUniqueId().toString(), p.getName(), 0);
}
});Always close the database when your plugin disables:
@Override
public void onDisable() {
if (db != null) db.close();
}