foreach-ui logo
codeLanguages
account_treeDSA

Quick Actions

quizlock Random Quiz
trending_uplock Progress
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • quiz
Java
  • Understand JDBC URL structure for different databases
  • Establish connections using DriverManager and DataSource
  • Implement connection pooling with HikariCP

Connecting to a Database

The Art of Database Connections

Before you can query, insert, or update data, you need to establish a connection. Think of a database connection as a phone call — you dial (connect), have a conversation (execute queries), and hang up (close). Managing this lifecycle properly is crucial for application performance and stability.

The JDBC URL: Your Database Address

Every database connection starts with a JDBC URL — a special string that tells Java exactly where and how to connect.

URL Anatomy

jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
└──┬─┘ └─┬─┘ └───┬────┘ └─┬┘ └─┬┘ └──────────────┬────────────┘
   │     │       │        │    │                  │
Protocol Subprotocol  Host   Port Database    Parameters

URL Patterns for Popular Databases

Database JDBC URL Pattern Example
MySQL jdbc:mysql://host:port/database jdbc:mysql://localhost:3306/shop
PostgreSQL jdbc:postgresql://host:port/database jdbc:postgresql://localhost:5432/shop
Oracle jdbc:oracle:thin:@host:port:sid jdbc:oracle:thin:@localhost:1521:orcl
SQL Server jdbc:sqlserver://host:port;database=name jdbc:sqlserver://localhost:1433;database=shop
H2 (Memory) jdbc:h2:mem:database jdbc:h2:mem:testdb
H2 (File) jdbc:h2:file:path jdbc:h2:file:./data/mydb
SQLite jdbc:sqlite:path jdbc:sqlite:./data.db

Establishing a Connection

The Classic Approach

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnector {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "secret";
        
        Connection connection = null;
        
        try {
            // Establish connection
            connection = DriverManager.getConnection(url, user, password);
            System.out.println("✓ Connected successfully!");
            
            // Use the connection...
            
        } catch (SQLException e) {
            System.err.println("✗ Connection failed: " + e.getMessage());
        } finally {
            // Always close in finally block
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

The Modern Way: Try-With-Resources

Java 7+ introduced a much cleaner approach — resources are automatically closed:

String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String password = "secret";

try (Connection connection = DriverManager.getConnection(url, user, password)) {
    System.out.println("✓ Connected successfully!");
    
    // Use the connection...
    // No need to explicitly close — it's automatic!
    
} catch (SQLException e) {
    System.err.println("✗ Connection failed: " + e.getMessage());
}
// Connection is automatically closed here, even if an exception occurred

💡 Best Practice: Always use try-with-resources for JDBC connections, statements, and result sets. It prevents resource leaks.

Connection Properties

Sometimes you need to configure more than just URL, username, and password:

import java.util.Properties;

Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "secret");
props.setProperty("useSSL", "true");
props.setProperty("serverTimezone", "UTC");
props.setProperty("autoReconnect", "true");
props.setProperty("characterEncoding", "UTF-8");

try (Connection conn = DriverManager.getConnection(url, props)) {
    // Connected with custom properties
}

Common Connection Properties

Property Purpose Example
useSSL Enable/disable SSL encryption true / false
serverTimezone Set server timezone UTC
autoReconnect Reconnect if connection drops true
characterEncoding Character set for data UTF-8
connectTimeout Connection timeout (ms) 5000
socketTimeout Socket read timeout (ms) 30000

Connection Validation

Before using a connection, especially from a pool, validate it:

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    
    // Method 1: isValid() - checks if connection is alive
    if (conn.isValid(5)) {  // 5 second timeout
        System.out.println("Connection is valid");
    }
    
    // Method 2: Check if closed
    if (!conn.isClosed()) {
        System.out.println("Connection is open");
    }
    
    // Method 3: Run a test query
    try (Statement stmt = conn.createStatement()) {
        stmt.execute("SELECT 1");
        System.out.println("Connection works!");
    }
}

The Problem: Connection Overhead

Creating a new connection for every operation is expensive:

┌─────────────────────────────────────────────────────────────────┐
│                   Connection Lifecycle                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  TCP Handshake → Authentication → Session Setup → Ready        │
│       ~50ms          ~20ms           ~30ms                      │
│                                                                 │
│  Total: ~100ms per connection (before any actual query!)       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

For a web application handling 1000 requests/second, this overhead is unacceptable.

The Solution: Connection Pooling

Connection pools maintain a cache of reusable connections:

┌───────────────────────────────────────────────────────────────┐
│                     Connection Pool                           │
├───────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐                          │
│  │Conn│ │Conn│ │Conn│ │Conn│ │Conn│  ← Pre-created           │
│  │ 1  │ │ 2  │ │ 3  │ │ 4  │ │ 5  │    connections           │
│  └────┘ └────┘ └────┘ └────┘ └────┘                          │
│    │                    ↑                                     │
│    ↓                    │                                     │
│  [Borrow]           [Return]                                  │
│                                                               │
│  Request → Get from pool → Use → Return to pool → Available  │
│              (~1ms)                  (~0ms)                   │
│                                                               │
└───────────────────────────────────────────────────────────────┘

HikariCP: The Fastest Pool

HikariCP is the industry standard for connection pooling:

<!-- Maven dependency -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

// Configure the pool
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("secret");

// Pool settings
config.setMaximumPoolSize(10);        // Max connections
config.setMinimumIdle(5);             // Min idle connections
config.setConnectionTimeout(30000);   // 30 seconds
config.setIdleTimeout(600000);        // 10 minutes
config.setMaxLifetime(1800000);       // 30 minutes

// Create the data source
HikariDataSource dataSource = new HikariDataSource(config);

// Use it
try (Connection conn = dataSource.getConnection()) {
    // Fast! Connection borrowed from pool
    // Use connection...
}
// Connection returned to pool, not closed

// When application shuts down
dataSource.close();

Pool Size Guidelines

Application Type Min Pool Max Pool
Small web app 5 10
Medium web app 10 20
High-traffic app 20 50

🎯 Rule of Thumb: connections = ((core_count * 2) + effective_spindle_count)
For most apps: 10-20 is a good starting point.

DataSource vs DriverManager

Feature DriverManager DataSource
Connection Pooling No Yes
Configuration In code Externalized
JNDI Support No Yes
Production Use Not recommended Recommended

DataSource Pattern

public class DatabaseConfig {
    private static HikariDataSource dataSource;
    
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        config.setUsername("root");
        config.setPassword("secret");
        config.setMaximumPoolSize(10);
        
        dataSource = new HikariDataSource(config);
    }
    
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    
    public static void shutdown() {
        if (dataSource != null) {
            dataSource.close();
        }
    }
}

// Usage
try (Connection conn = DatabaseConfig.getConnection()) {
    // Use connection
}

Handling Connection Errors

Be prepared for things to go wrong:

try (Connection conn = dataSource.getConnection()) {
    // Work with database
} catch (SQLTimeoutException e) {
    // Connection timeout
    System.err.println("Connection timed out: " + e.getMessage());
} catch (SQLTransientConnectionException e) {
    // Temporary issue - might succeed if retried
    System.err.println("Temporary connection issue: " + e.getMessage());
} catch (SQLNonTransientConnectionException e) {
    // Permanent issue - wrong credentials, host down, etc.
    System.err.println("Connection error: " + e.getMessage());
} catch (SQLException e) {
    // General SQL error
    System.err.println("Database error: " + e.getMessage());
    System.err.println("SQL State: " + e.getSQLState());
    System.err.println("Error Code: " + e.getErrorCode());
}

JDBC URLs contain protocol, host, port, database. DriverManager is simple but not for production. DataSource supports connection pooling. HikariCP is fast and reliable. Always use try-with-resources for automatic cleanup. Configure pool sizes based on your app's needs. Handle connection errors gracefully. Validate connections before use.

© 2026 forEach. All rights reserved.

Privacy Policy•Terms of Service