jdbc

Java Database Connectivity (JDBC) is an API provided by Java that allows developers to connect and interact with databases. With Java 21, new enhancements in the language and libraries further improve JDBC usage, making database operations more efficient and developer-friendly.

This tutorial will cover:

  1. Setting up JDBC.

  2. Connecting to a database.

  3. Executing queries and updates.

  4. Best practices and new features in Java 21.

Setting Up JDBC

JDBC Architecture

Prerequisites:

  • Java 21 installed.

  • A database system like MySQL, PostgreSQL, or SQLite.

  • JDBC Driver for your database (e.g., MySQL Connector/J for MySQL).

Adding Dependencies

For Maven projects, include the required dependencies in your pom.xml:


<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.34</version>
    </dependency>
</dependencies>
 

For Gradle projects, add the dependency to your build.gradle:


dependencies {
    implementation 'mysql:mysql-connector-j:8.0.34'
}

2. Connecting to a Database

Example Connection Code


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

public class DatabaseConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/my_database";
    private static final String USER = "root";
    private static final String PASSWORD = "password";

    public static Connection connect() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public static void main(String[] args) {
        try (Connection connection = connect()) {
            System.out.println("Connected to the database successfully!");
        } catch (SQLException e) {
            System.err.println("Connection failed: " + e.getMessage());
        }
    }
}


Explanation

  • URL: Specifies the database location and name.

  • USER/PASSWORD: The credentials to access the database.

  • The DriverManager.getConnection method establishes the connection.

  • Java 21 supports connection pooling for improved performance.


Executing Queries and Updates

Query Example: Fetching Data


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

public class DatabaseConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/my_database";
    private static final String USER = "root";
    private static final String PASSWORD = "password";

    public static Connection connect() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public static void main(String[] args) {
        try (Connection connection = connect()) {
            System.out.println("Connected to the database successfully!");
        } catch (SQLException e) {
            System.err.println("Connection failed: " + e.getMessage());
        }
    }
}

Explanation

  • URL: Specifies the database location and name.

  • USER/PASSWORD: The credentials to access the database.

  • The DriverManager.getConnection method establishes the connection.

  • Java 21 supports connection pooling for improved performance.

Executing Queries and Updates

Query Example: Fetching Data


import java.sql.*;

public class QueryExample {
    public static void fetchData() {
        String query = "SELECT * FROM employees";

        try (Connection connection = DatabaseConnection.connect();
             Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery(query)) {

            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String department = resultSet.getString("department");
                System.out.printf("ID: %d, Name: %s, Department: %s%n", id, name, department);
            }
        } catch (SQLException e) {
            System.err.println("Query failed: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        fetchData();
    }
}


Update Example: Modifying Data


import java.sql.*;

public class QueryExample {
    public static void fetchData() {
        String query = "SELECT * FROM employees";

        try (Connection connection = DatabaseConnection.connect();
             Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery(query)) {

            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String department = resultSet.getString("department");
                System.out.printf("ID: %d, Name: %s, Department: %s%n", id, name, department);
            }
        } catch (SQLException e) {
            System.err.println("Query failed: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        fetchData();
    }
}

Update Example: Modifying Data

 

public class UpdateExample {
    public static void updateData() {
        String update = "UPDATE employees SET department = ? WHERE id = ?";

        try (Connection connection = DatabaseConnection.connect();
             PreparedStatement preparedStatement = connection.prepareStatement(update)) {

            preparedStatement.setString(1, "Marketing");
            preparedStatement.setInt(2, 101);

            int rowsAffected = preparedStatement.executeUpdate();
            System.out.println("Rows updated: " + rowsAffected);
        } catch (SQLException e) {
            System.err.println("Update failed: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        updateData();
    }
}

Best Practices and New Features in Java 21

Best Practices

  1. Use Connection Pooling:

    • Avoid creating and closing connections repeatedly by using connection pools like HikariCP or Apache DBCP.

  2. Use try-with-resources:

    • Ensure automatic resource management for Connection, Statement, and ResultSet objects.

  3. Prepared Statements:

    • Prevent SQL injection by using PreparedStatement for queries.

  4. Error Handling:

    • Handle exceptions gracefully and log errors for debugging.

New Features in Java 21

  • Virtual Threads (Preview):

    • With Project Loom, JDBC queries can be executed in lightweight threads, improving scalability for database-intensive applications.



 

import java.util.concurrent.Executors;

public class VirtualThreadExample {
    public static void main(String[] args) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            executor.submit(() -> {
                try (Connection connection = DatabaseConnection.connect()) {
                    System.out.println("Virtual thread handling connection");
                } catch (SQLException e) {
                    System.err.println("Error: " + e.getMessage());
                }
            });
        }
    }
}

Structured Concurrency API (Preview):

    • Manage multiple queries or database operations in parallel with improved error propagation and cancellation support.

 

import java.util.concurrent.*;

public class StructuredConcurrencyExample {
    public static void main(String[] args) {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            Future<Void> task1 = scope.fork(() -> {
                QueryExample.fetchData();
                return null;
            });
            Future<Void> task2 = scope.fork(() -> {
                UpdateExample.updateData();
                return null;
            });

            scope.join(); // Wait for all tasks to complete.
            scope.throwIfFailed();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}
 

Conclusion

 

JDBC remains a robust solution for database connectivity in Java. With the enhancements introduced in Java 21, developers can leverage modern features like virtual threads and structured concurrency to build highly scalable and efficient database applications.

 

By following the best practices and using the new APIs effectively, you can create robust, maintainable, and high-performance database applications.