JDBC ResultSet Interface with Examples

In this article, we will learn how to create a ResultSet interface and how to use ResultSet interface methods with examples.

JDBC ResultSet Interface Overview

The ResultSet interface provides methods for retrieving and manipulating the results of executed queries, and ResultSet objects can have different functionality and characteristics. These characteristics are a type, concurrency, and cursor holdability.

ResultSet Types

The type of a ResultSet object determines the level of its functionality in two areas: the ways in which the cursor can be manipulated, and how concurrent changes made to the underlying data source are reflected by the ResultSet object.
The sensitivity of a ResultSet object is determined by one of three different ResultSet types:

TYPE_FORWARD_ONLY

The result set cannot be scrolled; its cursor moves forward only, from before the first row to after the last row. The rows contained in the result set depend on how the underlying database generates the results. That is, it contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved.

TYPE_SCROLL_INSENSITIVE

The result can be scrolled; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. The result set is insensitive to changes made to the underlying data source while it is open. It contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved.

TYPE_SCROLL_SENSITIVE

The result can be scrolled; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. The result set reflects changes made to the underlying data source while the result set remains open.
The default ResultSet type is TYPE_FORWARD_ONLY.

ResultSet Concurrency

The concurrency of a ResultSet object determines what level of update functionality is supported.
There are two concurrency levels:
  1. CONCUR_READ_ONLY: The ResultSet object cannot be updated using the ResultSet interface.
  2. CONCUR_UPDATABLE: The ResultSet object can be updated using the ResultSet interface.
The default ResultSet concurrency is CONCUR_READ_ONLY.

Concurrency level - CONCUR_UPDATABLE Example

The below example demonstrates how to use a ResultSet object whose concurrency level is CONCUR_UPDATABLE.
public class ResultSetExamples {

    public static void main(String[] args) {
        modifyUserName();
        // batchUpdate();
        //parameterizedBatchUpdate();
        //insertRowInResultSetObject();
    }

    private static void modifyUserName() {
        String QUERY = "select id,name,email,country,password from Users where id = 1";
        try (Connection connection = DriverManager
            .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");
            // Step 2:Create a statement using connection object
            Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE);
            // Step 3: Execute the query or update query
            ResultSet rs = stmt.executeQuery(QUERY)) {
            // Step 4: Process the ResultSet object.
            while (rs.next()) {
                String name = rs.getString("name");
                System.out.println(" User name before update : " + name);
                rs.updateString("name", "Ramesh");
                rs.updateRow();
                System.out.println("User name after update  : " + rs.getString("name"));
            }
        } catch (SQLException e) {
            printSQLException(e);
        }
    }

    public static void printSQLException(SQLException ex) {
        for (Throwable e: ex) {
            if (e instanceof SQLException) {
                e.printStackTrace(System.err);
                System.err.println("SQLState: " + ((SQLException) e).getSQLState());
                System.err.println("Error Code: " + ((SQLException) e).getErrorCode());
                System.err.println("Message: " + e.getMessage());
                Throwable t = ex.getCause();
                while (t != null) {
                    System.out.println("Cause: " + t);
                    t = t.getCause();
                }
            }
        }
    }
}
Output:
User name before update : Ras
User name after update  : Ramesh

Cursor Holdability

Calling the method Connection.commit can close the ResultSet objects that have been created during the current transaction. In some cases, however, this may not be the desired behavior. The ResultSet property holdability gives the application control over whether ResultSet objects (cursors) are closed when a commit is called.
The following ResultSet constants may be supplied to the Connection methods createStatement, prepareStatement, and prepareCall:
  1. HOLD_CURSORS_OVER_COMMIT: ResultSet cursors are not closed; they are holdable: they are held open when the method commit is called. Holdable cursors might be ideal if your application uses mostly read-only ResultSet objects.
  2. CLOSE_CURSORS_AT_COMMIT: ResultSet objects (cursors) are closed when the commit method is called. Closing cursors when this method is called can result in better performance for some applications.
The default cursor holdability varies depending on your DBMS.
public static void cursorHoldabilitySupport(Connection conn)
    throws SQLException {

    DatabaseMetaData dbMetaData = conn.getMetaData();
    System.out.println("ResultSet.HOLD_CURSORS_OVER_COMMIT = " +
        ResultSet.HOLD_CURSORS_OVER_COMMIT);

    System.out.println("ResultSet.CLOSE_CURSORS_AT_COMMIT = " +
        ResultSet.CLOSE_CURSORS_AT_COMMIT);

    System.out.println("Default cursor holdability: " +
        dbMetaData.getResultSetHoldability());

    System.out.println("Supports HOLD_CURSORS_OVER_COMMIT? " +
        dbMetaData.supportsResultSetHoldability(
            ResultSet.HOLD_CURSORS_OVER_COMMIT));

    System.out.println("Supports CLOSE_CURSORS_AT_COMMIT? " +
        dbMetaData.supportsResultSetHoldability(
            ResultSet.CLOSE_CURSORS_AT_COMMIT));
}

Retrieving Column Values from Rows

The ResultSet interface declares getter methods (for example, getBoolean and getLong) for retrieving column values from the current row. You can retrieve values using either the index number of the column or the alias or name of the column. The column index is usually more efficient. Columns are numbered from 1. For maximum portability, a result set columns within each row should be read in left-to-right order, and each column should be read only once.
For example, the following method, main(), retrieves column values by number:
package com.javaguides.jdbc.statement.examples;

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

/**
 * Select Statement JDBC Example
 * @author Ramesh Fadatare
 *
 */
public class SelectStatementExample {
    private static final String QUERY = "select id,name,email,country,password from Users";

    public static void main(String[] args) {

        // using try-with-resources to avoid closing resources (boiler plate code)

        // Step 1: Establishing a Connection
        try (Connection connection = DriverManager
            .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");

            // Step 2:Create a statement using connection object
            Statement stmt = connection.createStatement();

            // Step 3: Execute the query or update query
            ResultSet rs = stmt.executeQuery(QUERY)) {

            // Step 4: Process the ResultSet object.
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                String country = rs.getString("country");
                String password = rs.getString("password");
                System.out.println(id + "," + name + "," + email + "," + country + "," + password);
            }
        } catch (SQLException e) {
            printSQLException(e);
        }
        // Step 4: try-with-resource statement will auto close the connection.
    }

    public static void printSQLException(SQLException ex) {
        for (Throwable e: ex) {
            if (e instanceof SQLException) {
                e.printStackTrace(System.err);
                System.err.println("SQLState: " + ((SQLException) e).getSQLState());
                System.err.println("Error Code: " + ((SQLException) e).getErrorCode());
                System.err.println("Message: " + e.getMessage());
                Throwable t = ex.getCause();
                while (t != null) {
                    System.out.println("Cause: " + t);
                    t = t.getCause();
                }
            }
        }
    }
}
Output:
1,Ramesh,tony@gmail.com,US,secret

Updating Rows in ResultSet Objects

You cannot update a default ResultSet object, and you can only move its cursor forward. However, you can create ResultSet objects that can be scrolled (the cursor can move backward or move to an absolute position) and updated.
The following method, modifyUserName(), updates the existing name with a new name:
private static void modifyUserName() {
    String QUERY = "select id,name,email,country,password from Users where id = 1";
    try (Connection connection = DriverManager
        .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");
        // Step 2:Create a statement using connection object
        Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
            ResultSet.CONCUR_UPDATABLE);
        // Step 3: Execute the query or update query
        ResultSet rs = stmt.executeQuery(QUERY)) {
        // Step 4: Process the ResultSet object.
        while (rs.next()) {
            String name = rs.getString("name");
            System.out.println(" User name before update : " + name);
            rs.updateString("name", "Ramesh");
            rs.updateRow();
            System.out.println("User name after update  : " + rs.getString("name"));
        }
    } catch (SQLException e) {
        printSQLException(e);
    }
}
Output:
User name before update : Ramesh
User name after update  : Ram

Using Statement Objects for Batch Updates

A Statement, PreparedStatement, and CallableStatement objects have a list of commands that are associated with them. The list, which is associated with a Statement object at its creation, is initially empty. You can add SQL commands to this list with the method addBatch and empty it with the method clearBatch. When you have finished adding statements to the list, call the method executeBatch to send them all to the database to be executed as a unit, or batch.
For example, the following method batchUpdate() adds four rows to the Users table with a batch update:
package com.javaguides.jdbc.resultset;

import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

public class ResultSetExamples {

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

    public static void printSQLException(SQLException ex) {
        for (Throwable e: ex) {
            if (e instanceof SQLException) {
                e.printStackTrace(System.err);
                System.err.println("SQLState: " + ((SQLException) e).getSQLState());
                System.err.println("Error Code: " + ((SQLException) e).getErrorCode());
                System.err.println("Message: " + e.getMessage());
                Throwable t = ex.getCause();
                while (t != null) {
                    System.out.println("Cause: " + t);
                    t = t.getCause();
                }
            }
        }
    }

    private static void batchUpdate() {
        try (Connection connection = DriverManager
            .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");
            // Step 2:Create a statement using connection object
            Statement statement = connection.createStatement()) {
            connection.setAutoCommit(false);
            statement.addBatch("INSERT INTO Users VALUES (13, 'Pramod', 'pramod@gmail.com', 'India', '123');");
            statement.addBatch("INSERT INTO Users VALUES (14, 'A', 'a@gmail.com', 'India', '123');");
            statement.addBatch("INSERT INTO Users VALUES (15, 'B', 'b@gmail.com', 'India', '123');");
            statement.addBatch("INSERT INTO Users VALUES (16, 'C', 'c@gmail.com', 'India', '123');");
            statement.addBatch("INSERT INTO Users VALUES (17, 'D', 'd@gmail.com', 'India', '123');");
            int[] updateCounts = statement.executeBatch();
            System.out.println(Arrays.toString(updateCounts));
            connection.commit();
        } catch (BatchUpdateException batchUpdateException) {
            printBatchUpdateException(batchUpdateException);
        } catch (SQLException e) {
            printSQLException(e);
        }
    }

    public static void printBatchUpdateException(BatchUpdateException b) {

        System.err.println("----BatchUpdateException----");
        System.err.println("SQLState:  " + b.getSQLState());
        System.err.println("Message:  " + b.getMessage());
        System.err.println("Vendor:  " + b.getErrorCode());
        System.err.print("Update counts:  ");
        int[] updateCounts = b.getUpdateCounts();

        for (int i = 0; i < updateCounts.length; i++) {
            System.err.print(updateCounts[i] + "   ");
        }
    }

}
The following line disables auto-commit mode for the Connection object con so that the transaction will not be automatically committed or rolled back when the method executeBatch is called.
connection.setAutoCommit(false);
To allow for correct error handling, you should always disable auto-commit mode before beginning a batch update.

Performing Parameterized Batch Update

It is also possible to have a parameterized batch update, as shown in the following code fragment, where the con is a Connection object:
private static void parameterizedBatchUpdate() {

    String INSERT_USERS_SQL = "INSERT INTO users" + "  (id, name, email, country, password) VALUES " +
        " (?, ?, ?, ?, ?);";

    try (Connection connection = DriverManager
        .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");
        // Step 2:Create a statement using connection object
        PreparedStatement preparedStatement = connection.prepareStatement(INSERT_USERS_SQL)) {
        connection.setAutoCommit(false);

        preparedStatement.setInt(1, 20);
        preparedStatement.setString(2, "a");
        preparedStatement.setString(3, "a@gmail.com");
        preparedStatement.setString(4, "India");
        preparedStatement.setString(5, "secret");
        preparedStatement.addBatch();

        preparedStatement.setInt(1, 21);
        preparedStatement.setString(2, "b");
        preparedStatement.setString(3, "b@gmail.com");
        preparedStatement.setString(4, "India");
        preparedStatement.setString(5, "secret");
        preparedStatement.addBatch();

        preparedStatement.setInt(1, 22);
        preparedStatement.setString(2, "c");
        preparedStatement.setString(3, "c@gmail.com");
        preparedStatement.setString(4, "India");
        preparedStatement.setString(5, "secret");
        preparedStatement.addBatch();

        preparedStatement.setInt(1, 23);
        preparedStatement.setString(2, "d");
        preparedStatement.setString(3, "d@gmail.com");
        preparedStatement.setString(4, "India");
        preparedStatement.setString(5, "secret");
        preparedStatement.addBatch();

        int[] updateCounts = preparedStatement.executeBatch();
        System.out.println(Arrays.toString(updateCounts));
        connection.commit();
        connection.setAutoCommit(true);
    } catch (BatchUpdateException batchUpdateException) {
        printBatchUpdateException(batchUpdateException);
    } catch (SQLException e) {
        printSQLException(e);
    }
}

Inserting Rows in ResultSet Objects

The following method, insertRowInResultSetObject(), inserts a row into the Users table through a ResultSet object:
private static void insertRowInResultSetObject() {
    String QUERY = "select id,name,email,country,password from Users where id = 1";
    try (Connection connection = DriverManager
        .getConnection("jdbc:mysql://localhost:3306/mysql_database?useSSL=false", "root", "root");
        // Step 2:Create a statement using connection object
        Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
            ResultSet.CONCUR_UPDATABLE);
        // Step 3: Execute the query or update query
        ResultSet uprs = stmt.executeQuery(QUERY)) {
        uprs.moveToInsertRow();
        uprs.updateInt(1, 25);
        uprs.updateString(2, "b");
        uprs.updateString(3, "b@gmail.com");
        uprs.updateString(4, "India");
        uprs.updateString(5, "secret");
        uprs.insertRow();
        uprs.beforeFirst();

    } catch (SQLException e) {
        printSQLException(e);
    }
}



Comments