GroupeZ Docs
Getting Started

Database Connections

Sarah supports multiple database systems through a unified interface. This guide covers how to configure and manage database connections.

The examples use Sarah's Logger. To use your plugin's Java logger:

Logger logger = JULogger.from(getLogger());

Supported Databases

DatabaseConnection ClassConfiguration Method
MySQLMySqlConnectionDatabaseConfiguration.create()
MariaDBMariaDbConnectionDatabaseConfiguration.createMariaDb()
PostgreSQLPostgreSqlConnectionDatabaseConfiguration.createPostgreSql()
SQLiteSqliteConnectionDatabaseConfiguration.sqlite()

MySQL Connection

Basic Setup

DatabaseConfiguration config = DatabaseConfiguration.create(
    "username",     // Database user
    "password",     // Database password
    3306,           // Port
    "localhost",    // Host
    "my_database"   // Database name
);

DatabaseConnection connection = new MySqlConnection(config, logger);
connection.connect();

With Debug Mode

Enable SQL query logging for debugging:

DatabaseConfiguration config = DatabaseConfiguration.create(
    "username",
    "password",
    3306,
    "localhost",
    "my_database",
    true  // Enable debug mode
);

MariaDB Connection

MariaDB configuration is similar to MySQL:

DatabaseConfiguration config = DatabaseConfiguration.createMariaDb(
    "username",
    "password",
    3306,
    "localhost",
    "my_database"
);

DatabaseConnection connection = new MariaDbConnection(config, logger);
connection.connect();

Without Port (Default 3306)

DatabaseConfiguration config = DatabaseConfiguration.createMariaDb(
    "username",
    "password",
    "localhost",
    "my_database"
);

PostgreSQL Connection

Add the org.postgresql:postgresql JDBC driver to your application, as described in the installation guide.

Basic Setup

DatabaseConfiguration config = DatabaseConfiguration.createPostgreSql(
    "username",     // Database user
    "password",     // Database password
    5432,           // Port
    "localhost",    // Host
    "my_database",  // Database name
    false           // Debug mode
);

DatabaseConnection connection = new PostgreSqlConnection(config, logger);
connection.connect();

This configuration uses DatabaseType.POSTGRESQL. To use a pool, pass the same configuration to HikariDatabaseConnection.

Column Names

Sarah converts identifier backticks to double quotes before sending a statement to PostgreSQL. Quoted identifiers are case-sensitive: use the same case when creating columns and querying them. See column types for PostgreSQL equivalents and timestamp behavior.

SQLite Connection

SQLite is perfect for development or small projects:

// Create configuration
DatabaseConfiguration config = DatabaseConfiguration.sqlite(true); // debug mode

// Create connection with folder path
// The database file will be created as "database.db" in this folder
DatabaseConnection connection = new SqliteConnection(config, myPluginFolder, logger);
connection.connect();

Journal Mode and Lock Timeout

Set the options before connecting:

SqliteConnection connection = new SqliteConnection(config, myPluginFolder, logger);
connection.setJournalMode("WAL");
connection.setBusyTimeout(5000);
connection.connect();

setJournalMode applies the journal mode to each connection. WAL lets readers work while a write is in progress. setBusyTimeout sets how many milliseconds to wait for a lock before failing with SQLITE_BUSY. null keeps the driver defaults. Use getJournalMode() and getBusyTimeout() to read these settings.

Complete SQLite Example

public class MyPlugin extends JavaPlugin {

    private DatabaseConnection connection;

    @Override
    public void onEnable() {
        DatabaseConfiguration config = DatabaseConfiguration.sqlite(false);
        this.connection = new SqliteConnection(config, getDataFolder(), JULogger.from(getLogger()));

        try {
            connection.connect();
            getLogger().info("Connected to SQLite database!");
        } catch (DatabaseException e) {
            getLogger().severe("Failed to connect to SQLite!");
            e.printStackTrace();
        }
    }
}

DatabaseConfiguration Methods

Factory Methods

MethodDescription
create(user, password, port, host, database)Create MySQL config
create(user, password, port, host, database, debug)Create MySQL config with debug
createMariaDb(user, password, port, host, database)Create MariaDB config
createMariaDb(user, password, port, host, database, debug)Create MariaDB config with debug
createPostgreSql(user, password, port, host, database, debug)Create PostgreSQL config
sqlite(debug)Create SQLite config

Instance Methods

MethodReturn TypeDescription
getUser()StringGet database username
getPassword()StringGet database password
getPort()intGet database port
getHost()StringGet database host
getDatabase()StringGet database name
isDebug()booleanCheck if debug mode is enabled
getDatabaseType()DatabaseTypeGet the database type enum
replacePrefix(tableName)StringReplace table prefix
getMaximumPoolSize()IntegerGet the pool size, null for the default
getMinimumIdle()IntegerGet the minimum idle connections, null for the default
getMaxLifetime()LongGet the connection lifetime in milliseconds, null for the default (1.26+)
getTablePrefix()StringGet the table prefix
getDialect()DialectGet the dialect for the configured engine
prepare(sql)StringReplace the prefix and adapt SQL quoting for the engine
getConnectionTimeout()LongGet the pooled connection timeout in milliseconds, null for the default
getLeakDetectionThreshold()LongGet the leak detection threshold in milliseconds, null for the default
getProperties()Map<String, String>Get driver properties set with withProperty

Driver Properties

withProperty(key, value) adds or replaces a property for plain and pooled connections. The method returns a new configuration: keep its result.

DatabaseConfiguration config = DatabaseConfiguration.createPostgreSql(
    "username", "password", 5432, "localhost", "my_database", false)
    .withProperty("sslmode", "require");

For MySQL and MariaDB, withProperty("useSSL", "true") enables SSL and withProperty("allowMultiQueries", "false") disables multiple statements, which Sarah enables by default.

Dialects and Prefixes

getDialect() exposes MySqlDialect, MariaDbDialect, SqliteDialect or PostgreSqlDialect depending on the configuration. Sarah's queries use this dialect automatically.

DatabaseConfiguration config = new DatabaseConfiguration(
    "game_", "username", "password", 5432, "localhost", "my_database", false,
    DatabaseType.POSTGRESQL);
String sql = config.prepare("SELECT `name` FROM %prefix%players");
// SELECT "name" FROM game_players

replacePrefix only replaces %prefix%. prepare also adapts identifier backticks to double quotes for PostgreSQL, leaving SQL strings in single quotes unchanged.

Connection Pool (HikariCP)

HikariDatabaseConnection opens a HikariCP pool for MySQL, MariaDB and PostgreSQL. Its settings are tuned on the DatabaseConfiguration, each with... method returns a new configuration:

DatabaseConfiguration config = DatabaseConfiguration.create("username", "password", 3306, "localhost", "my_database", false, DatabaseType.MYSQL)
        .withPoolSettings(10, 2)                         // maximum pool size, minimum idle
        .withMaxLifetime(TimeUnit.MINUTES.toMillis(10))
        .withTimeouts(10000L, 0L);                       // wait timeout, disable leak detection

DatabaseConnection connection = new HikariDatabaseConnection(config, logger);
MethodDescriptionDefault (null)
withPoolSettings(maximumPoolSize, minimumIdle)Pool size and idle connections kept opencores * 2 + 1, and min(pool size, 10)
withMaxLifetime(maxLifetime)Lifetime of a connection in milliseconds before it is retired. 0 keeps connections until the pool closes. HikariCP replaces values below 30 seconds with its default30 minutes
withTimeouts(connectionTimeout, leakDetectionThreshold)Connection wait timeout and leak detection threshold, in milliseconds. 0 disables leak detection10 seconds for each setting

SQLite cannot use this pool: use SqliteConnection. A long transaction can exceed the leak detection threshold without being a leak; tune the threshold for your usage.

Set the max lifetime a few minutes below the database wait_timeout, or below the idle timeout of a proxy in front of it, so the pool never hands out a connection the server already closed.

Connection Lifecycle

Connecting

try {
    connection.connect();
} catch (DatabaseException e) {
    // Handle connection failure
    e.printStackTrace();
}

Disconnecting

Always disconnect when your plugin disables:

@Override
public void onDisable() {
    if (connection != null) {
        connection.disconnect();
    }
}

Getting Raw Connection

If you need the underlying JDBC connection:

try (Connection jdbcConnection = connection.getConnection()) {
    // Use the JDBC connection here
}

Each getConnection() call opens a dedicated connection or borrows one from the pool. The caller must close it; with HikariCP, close() returns it to the pool. RequestHelper handles this cleanup for its own queries.

Logging

Logger exposes info, warn and error. For a custom logger implementing only info, the other methods delegate to info by default. JULogger.from(getLogger()) uses Java's INFO, WARNING and SEVERE levels.

Connection failures are logged with error. DatabaseConfiguration.toString() masks the password.

Best Practices

1. Always Handle Exceptions

try {
    connection.connect();
} catch (DatabaseException e) {
    logger.error("Database connection failed: " + e.getMessage());
    // Disable plugin or use fallback
}

2. Use SQLite for Development

boolean isDevelopment = true; // or from config

if (isDevelopment) {
    connection = new SqliteConnection(DatabaseConfiguration.sqlite(true), folder, logger);
} else {
    connection = new MySqlConnection(productionConfig, logger);
}

3. Close Connections Properly

@Override
public void onDisable() {
    // Save pending data first
    saveAllData();

    // Then disconnect
    if (connection != null) {
        connection.disconnect();
    }
}

Next Steps

On this page

GroupeZ MCP

Documentation in your AI

MCP lets your AI search GroupeZ documentation and read current examples to help you configure your plugins.

Read-only · No documentation API key needed

1. Copy the server URL

Transport: HTTP (Streamable HTTP). Authentication: none. Your tool uses its own model and subscription limits.

  1. Open Plugins in ChatGPT on the web, then + → Add custom MCP server.
  2. Name it ‘GroupeZ Documentation’, paste the URL above and choose ‘No authentication’. Create and install the plugin.
  3. In a conversation, type @ and select the plugin before asking. If needed, enable search, get_page and list_pages in its settings.
Official setup guide

3. Ask a question

Use GroupeZ MCP to help me create a zMenu inventory. Search relevant pages, read the examples and cite your sources.
Other clients and troubleshooting

For clients using mcpServers, adapt this example to their format:

{
  "mcpServers": {
    "groupez-docs": {
      "url": ""
    }
  }
}

Available tools are search, get_page and list_pages. Refresh the connector’s tools after updates. If your AI cannot access them, check that the connector is enabled in the conversation and your account allows custom MCP servers. Opening the URL in a browser is not an MCP test.