JDBC: Connecting Java to a Database

    Atul Kabra3 min readUpdated

    JDBC (Java Database Connectivity) is the standard API for talking to relational databases from Java. With JDBC you open a Connection, send SQL through a Statement or — far safer — a PreparedStatement, and read query results from a ResultSet. The same code works across databases (MySQL, PostgreSQL, SQLite, and more) because each provides a JDBC driver that plugs in behind the standard interfaces.

    What you need

    1. A running database and its connection URL.
    2. The JDBC driver for that database on your classpath (usually a single .jar you add via Maven or Gradle).
    3. JDBC itself, which is part of the standard java.sql package.

    Opening a connection

    A JDBC URL has the form jdbc:<database>://host:port/dbname. Always close connections — try-with-resources does this for you.

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    String url = "jdbc:mysql://localhost:3306/school";
    String user = "appuser";
    String password = "secret"; // in real apps, load from config, never hard-code
    
    // try-with-resources closes the connection automatically.
    try (Connection conn = DriverManager.getConnection(url, user, password)) {
        System.out.println("Connected!");
    } catch (SQLException e) {
        System.out.println("Connection failed: " + e.getMessage());
    }
    

    Querying with PreparedStatement

    Use PreparedStatement with ? placeholders rather than building SQL by string concatenation. This is both safer (it prevents SQL injection) and often faster.

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    String sql = "SELECT name, marks FROM students WHERE marks >= ?";
    try (Connection conn = DriverManager.getConnection(url, user, password);
         PreparedStatement ps = conn.prepareStatement(sql)) {
    
        ps.setInt(1, 40); // bind 40 to the first placeholder, safely
    
        try (ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {                 // advance row by row
                String name = rs.getString("name");
                int marks = rs.getInt("marks");
                System.out.println(name + ": " + marks);
            }
        }
    }
    

    executeQuery() runs a SELECT and returns a ResultSet you walk with next(). Column values are read by name or index.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    Inserting and updating

    For statements that change data (INSERT, UPDATE, DELETE), use executeUpdate(), which returns the number of affected rows.

    String insert = "INSERT INTO students (name, marks) VALUES (?, ?)";
    try (Connection conn = DriverManager.getConnection(url, user, password);
         PreparedStatement ps = conn.prepareStatement(insert)) {
    
        ps.setString(1, "Asha");
        ps.setInt(2, 72);
        int rows = ps.executeUpdate(); // returns 1 if one row inserted
        System.out.println("Inserted " + rows + " row(s)");
    }
    

    Why never concatenate SQL

    Building a query like "... WHERE name = '" + userInput + "'" invites SQL injection — a malicious value can change the query's meaning. PreparedStatement parameters are sent separately from the SQL text, so the input can never be interpreted as code. Always parameterise user input.

    Transactions (brief)

    By default each statement auto-commits. To group several changes so they all succeed or all fail, turn off auto-commit, then commit() or rollback().

    conn.setAutoCommit(false);
    try {
        // ... several executeUpdate calls ...
        conn.commit();   // make all changes permanent together
    } catch (SQLException e) {
        conn.rollback(); // undo everything on failure
    }
    

    Common mistakes

    • Building SQL by string concatenation. This is the classic SQL-injection bug. Use PreparedStatement placeholders.
    • Not closing resources. Open connections and statements leak. Use try-with-resources.
    • Forgetting the driver dependency. Without the database's JDBC driver on the classpath, getConnection fails with "No suitable driver".
    • Calling getInt/getString before rs.next(). A fresh ResultSet points before the first row; you must call next() first.
    • Hard-coding credentials. Load them from configuration or environment variables, not source code.

    FAQ

    Do I still need Class.forName(...) to load the driver? Modern JDBC (4.0+) auto-discovers drivers on the classpath, so the explicit Class.forName call is usually unnecessary.

    Should I use JDBC directly in big apps? JDBC is the foundation; larger projects often layer a framework (such as an ORM) on top, but understanding raw JDBC makes those tools far clearer.

    Keep going

    Next, read and write files with File I/O in Java, or revisit Exception Handling in Java. All tutorials are on the Java hub; for guided practice in Jalgaon, see the Java course.


    Build database-backed apps at Infoplanet, Jalgaon. Join the waitlist for the Java course.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides