H2 Database Engine - A very fast, open source, JDBC API database with embedded and server modes, transaction support, multi-version concurrency, browser-based console application, encrypted databases, fulltext search, and pure Java implementation with small footprint
—
H2 Database Engine provides multiple server components for deploying databases in client/server mode. This includes TCP servers for database connections, web servers for the H2 Console administration interface, and PostgreSQL compatibility servers for existing PostgreSQL client applications.
High-performance TCP/IP database server for client connections.
public class TcpServer implements Service {
// Server lifecycle
public void start() throws SQLException;
public void stop();
public boolean isRunning(boolean traceError);
// Configuration
public String getURL();
public int getPort();
public String getStatus();
public boolean getAllowOthers();
public void setPort(int port);
public void setAllowOthers(boolean allowOthers);
// SSL support
public void setSSL(boolean ssl);
public boolean getSSL();
}Usage Examples:
// Start TCP server programmatically
TcpServer server = new TcpServer();
server.setPort(9092);
server.setAllowOthers(true); // Allow remote connections
server.start();
System.out.println("Server running at: " + server.getURL());
System.out.println("Server status: " + server.getStatus());
// Stop server
server.stop();Command Line Usage:
# Start TCP server on default port 9092
java -cp h2-*.jar org.h2.tools.Server -tcp
# Start on custom port with remote access
java -cp h2-*.jar org.h2.tools.Server -tcp -tcpPort 9093 -tcpAllowOthers
# Start with SSL encryption
java -cp h2-*.jar org.h2.tools.Server -tcp -tcpSSL -tcpPort 9094Client Connection:
// Connect to TCP server
Connection conn = DriverManager.getConnection(
"jdbc:h2:tcp://localhost:9092/~/mydb", "sa", "password");
// SSL connection
Connection sslConn = DriverManager.getConnection(
"jdbc:h2:ssl://localhost:9094/~/mydb", "sa", "password");HTTP server providing the H2 Console web-based administration interface.
public class WebServer implements Service {
// Server lifecycle
public void start() throws SQLException;
public void stop();
public boolean isRunning(boolean traceError);
// Configuration
public String getURL();
public int getPort();
public String getStatus();
public boolean getAllowOthers();
public void setPort(int port);
public void setAllowOthers(boolean allowOthers);
// SSL and security
public void setSSL(boolean ssl);
public boolean getSSL();
public void setAllowSecureCreation(boolean allowSecureCreation);
// Authentication
public void setCommandHistoryAllowed(boolean allowed);
public void setShutdownHandler(ShutdownHandler shutdownHandler);
}Usage Examples:
// Start web console programmatically
WebServer webServer = new WebServer();
webServer.setPort(8082);
webServer.setAllowOthers(true); // Allow remote access
webServer.start();
System.out.println("H2 Console available at: " + webServer.getURL());
// Configure for production
webServer.setAllowSecureCreation(false); // Disable database creation via web
webServer.setCommandHistoryAllowed(false); // Disable command history
// Stop server
webServer.stop();Command Line Usage:
# Start web console on default port 8082
java -cp h2-*.jar org.h2.tools.Server -web
# Start on custom port with remote access
java -cp h2-*.jar org.h2.tools.Server -web -webPort 8083 -webAllowOthers
# Start with SSL
java -cp h2-*.jar org.h2.tools.Server -web -webSSL -webPort 8443
# Disable browser opening
java -cp h2-*.jar org.h2.tools.Server -web -webDaemonWeb Console Access:
http://localhost:8082https://localhost:8443 (with SSL)PostgreSQL protocol compatibility server for existing PostgreSQL clients.
public class PgServer implements Service {
// Server lifecycle
public void start() throws SQLException;
public void stop();
public boolean isRunning(boolean traceError);
// Configuration
public String getURL();
public int getPort();
public String getStatus();
public boolean getAllowOthers();
public void setPort(int port);
public void setAllowOthers(boolean allowOthers);
// PostgreSQL compatibility
public void setKeyFile(String keyFile);
public void setKey(String key, String value);
}Usage Examples:
// Start PostgreSQL compatibility server
PgServer pgServer = new PgServer();
pgServer.setPort(5435); // Different from default PostgreSQL port 5432
pgServer.setAllowOthers(true);
pgServer.start();
System.out.println("PostgreSQL server available at: " + pgServer.getURL());
// Stop server
pgServer.stop();Command Line Usage:
# Start PostgreSQL server on default port 5435
java -cp h2-*.jar org.h2.tools.Server -pg
# Start on custom port
java -cp h2-*.jar org.h2.tools.Server -pg -pgPort 5436 -pgAllowOthersPostgreSQL Client Connection:
# Connect using psql
psql -h localhost -p 5435 -U sa -d ~/mydb
# Connection string for PostgreSQL clients
postgresql://sa@localhost:5435/~/mydbStart multiple server types simultaneously:
public class Server extends Tool implements Runnable, ShutdownHandler {
// Factory methods for specific servers
public static Server createTcpServer(String... args) throws SQLException;
public static Server createWebServer(String... args) throws SQLException;
public static Server createPgServer(String... args) throws SQLException;
// Combined server management
public static void main(String... args);
public Server start() throws SQLException;
public void stop();
public String getStatus();
}Usage Examples:
// Start all servers programmatically
Server tcpServer = Server.createTcpServer("-tcpPort", "9092", "-tcpAllowOthers");
Server webServer = Server.createWebServer("-webPort", "8082", "-webAllowOthers");
Server pgServer = Server.createPgServer("-pgPort", "5435", "-pgAllowOthers");
tcpServer.start();
webServer.start();
pgServer.start();
System.out.println("All servers started");
System.out.println("TCP: " + tcpServer.getURL());
System.out.println("Web: " + webServer.getURL());
System.out.println("PG: " + pgServer.getURL());
// Stop all servers
tcpServer.stop();
webServer.stop();
pgServer.stop();Command Line Combined Startup:
# Start all server types
java -cp h2-*.jar org.h2.tools.Server -tcp -web -pg
# With custom ports
java -cp h2-*.jar org.h2.tools.Server \
-tcp -tcpPort 9092 -tcpAllowOthers \
-web -webPort 8082 -webAllowOthers \
-pg -pgPort 5435 -pgAllowOtherspublic class TcpServerConfig {
public static void startConfiguredTcpServer() throws SQLException {
TcpServer server = new TcpServer();
// Basic configuration
server.setPort(9092);
server.setAllowOthers(true);
// Performance tuning
server.setDaemon(true); // Run as daemon thread
// Security
server.setSSL(true); // Enable SSL/TLS
server.start();
// Server information
System.out.println("TCP Server Configuration:");
System.out.println(" URL: " + server.getURL());
System.out.println(" Port: " + server.getPort());
System.out.println(" SSL: " + server.getSSL());
System.out.println(" Allow Others: " + server.getAllowOthers());
System.out.println(" Status: " + server.getStatus());
}
}public class WebServerConfig {
public static void startConfiguredWebServer() throws SQLException {
WebServer server = new WebServer();
// Basic configuration
server.setPort(8082);
server.setAllowOthers(true);
// Security settings
server.setSSL(true);
server.setAllowSecureCreation(false); // Prevent database creation
server.setCommandHistoryAllowed(false); // Disable command history
// Add shutdown handler
server.setShutdownHandler(new ShutdownHandler() {
@Override
public void shutdown() {
System.out.println("Web server shutting down...");
}
});
server.start();
System.out.println("Web Console available at: " + server.getURL());
}
}All server components implement the Service interface:
public interface Service {
void start() throws SQLException;
void stop();
boolean isRunning(boolean traceError);
String getURL();
int getPort();
String getStatus();
}Custom Service Implementation:
public class CustomDatabaseService implements Service {
private TcpServer tcpServer;
private WebServer webServer;
private boolean running = false;
@Override
public void start() throws SQLException {
tcpServer = new TcpServer();
tcpServer.setPort(9092);
tcpServer.setAllowOthers(true);
webServer = new WebServer();
webServer.setPort(8082);
webServer.setAllowOthers(false); // Local access only for web console
tcpServer.start();
webServer.start();
running = true;
System.out.println("Custom database service started");
}
@Override
public void stop() {
if (tcpServer != null) tcpServer.stop();
if (webServer != null) webServer.stop();
running = false;
System.out.println("Custom database service stopped");
}
@Override
public boolean isRunning(boolean traceError) {
return running &&
(tcpServer == null || tcpServer.isRunning(traceError)) &&
(webServer == null || webServer.isRunning(traceError));
}
@Override
public String getURL() {
return tcpServer != null ? tcpServer.getURL() : null;
}
@Override
public int getPort() {
return tcpServer != null ? tcpServer.getPort() : -1;
}
@Override
public String getStatus() {
return "TCP: " + (tcpServer != null ? tcpServer.getStatus() : "stopped") +
", Web: " + (webServer != null ? webServer.getStatus() : "stopped");
}
}Integrate H2 Console into existing web applications:
public class WebServlet extends HttpServlet {
// Servlet lifecycle
public void init() throws ServletException;
public void destroy();
// HTTP methods
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}Web.xml Configuration:
<servlet>
<servlet-name>H2Console</servlet-name>
<servlet-class>org.h2.server.web.WebServlet</servlet-class>
<init-param>
<param-name>webAllowOthers</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>H2Console</servlet-name>
<url-pattern>/h2-console/*</url-pattern>
</servlet-mapping>Jakarta EE support for modern application servers:
public class JakartaWebServlet extends HttpServlet {
// Same interface as WebServlet but for Jakarta EE
public void init() throws ServletException;
public void destroy();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}FROM openjdk:11-jre-slim
# Add H2 database jar
COPY h2-*.jar /app/h2.jar
# Create data directory
RUN mkdir -p /data
# Expose ports
EXPOSE 9092 8082 5435
# Start H2 servers
CMD ["java", "-cp", "/app/h2.jar", "org.h2.tools.Server", \
"-tcp", "-tcpAllowOthers", "-tcpPort", "9092", \
"-web", "-webAllowOthers", "-webPort", "8082", \
"-pg", "-pgAllowOthers", "-pgPort", "5435", \
"-baseDir", "/data"][Unit]
Description=H2 Database Server
After=network.target
[Service]
Type=simple
User=h2
Group=h2
ExecStart=/usr/bin/java -cp /opt/h2/h2.jar org.h2.tools.Server \
-tcp -tcpAllowOthers -tcpPort 9092 \
-web -webAllowOthers -webPort 8082 \
-baseDir /var/lib/h2
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target@Singleton
@Startup
public class H2ServerManager {
private Server tcpServer;
private Server webServer;
@PostConstruct
public void startServers() {
try {
// Start TCP server for application connections
tcpServer = Server.createTcpServer(
"-tcpPort", "9092",
"-tcpAllowOthers", "true",
"-baseDir", System.getProperty("h2.baseDir", "./data")
);
tcpServer.start();
// Start web console (development only)
if (isDevelopmentMode()) {
webServer = Server.createWebServer(
"-webPort", "8082",
"-webAllowOthers", "false"
);
webServer.start();
}
System.out.println("H2 servers started successfully");
} catch (SQLException e) {
throw new RuntimeException("Failed to start H2 servers", e);
}
}
@PreDestroy
public void stopServers() {
if (tcpServer != null) {
tcpServer.stop();
System.out.println("TCP server stopped");
}
if (webServer != null) {
webServer.stop();
System.out.println("Web server stopped");
}
}
private boolean isDevelopmentMode() {
return "development".equals(System.getProperty("app.profile"));
}
}public class LoadBalancedH2Pool {
private final List<String> serverUrls;
private final List<JdbcConnectionPool> pools;
private final AtomicInteger currentIndex = new AtomicInteger(0);
public LoadBalancedH2Pool(List<String> serverUrls, String user, String password) {
this.serverUrls = new ArrayList<>(serverUrls);
this.pools = serverUrls.stream()
.map(url -> JdbcConnectionPool.create(url, user, password))
.collect(Collectors.toList());
// Configure each pool
pools.forEach(pool -> {
pool.setMaxConnections(10);
pool.setTimeoutMs(5000);
});
}
public Connection getConnection() throws SQLException {
SQLException lastException = null;
// Try each server in round-robin fashion
for (int i = 0; i < pools.size(); i++) {
int index = currentIndex.getAndIncrement() % pools.size();
JdbcConnectionPool pool = pools.get(index);
try {
return pool.getConnection();
} catch (SQLException e) {
lastException = e;
System.err.println("Failed to connect to server: " + serverUrls.get(index));
}
}
throw new SQLException("All H2 servers unavailable", lastException);
}
public void shutdown() {
pools.forEach(JdbcConnectionPool::dispose);
}
}public class H2ServerMonitor {
private final List<Service> services;
public H2ServerMonitor(List<Service> services) {
this.services = services;
}
public ServerStatus getOverallStatus() {
boolean allRunning = true;
StringBuilder statusReport = new StringBuilder();
for (Service service : services) {
boolean running = service.isRunning(false);
allRunning &= running;
statusReport.append(service.getClass().getSimpleName())
.append(" (port ").append(service.getPort()).append("): ")
.append(running ? "RUNNING" : "STOPPED")
.append("\n");
}
return new ServerStatus(allRunning, statusReport.toString());
}
public static class ServerStatus {
private final boolean allRunning;
private final String report;
public ServerStatus(boolean allRunning, String report) {
this.allRunning = allRunning;
this.report = report;
}
public boolean isAllRunning() { return allRunning; }
public String getReport() { return report; }
}
}
// Usage
List<Service> services = Arrays.asList(tcpServer, webServer, pgServer);
H2ServerMonitor monitor = new H2ServerMonitor(services);
// Periodic health check
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
ServerStatus status = monitor.getOverallStatus();
if (!status.isAllRunning()) {
System.err.println("Server health check failed:\n" + status.getReport());
// Send alert, restart services, etc.
}
}, 0, 30, TimeUnit.SECONDS);Install with Tessl CLI
npx tessl i tessl/maven-com-h2database--h2