ResultSet in Java

Naveen AnamaneniUpdated · 7 min read

A ResultSet is the object that holds the rows returned by a query. It works with a cursor that points at one row at a time. The cursor starts before the first row; each call to next() moves it forward one row and returns false when there are no more. While the cursor is on a row, getter methods such as getInt and getString read that row's columns. By default a result set can only move forward and is read-only, but you can ask for one that scrolls in any direction or even updates the table. In this lesson, you will learn the cursor, the getters, how to deal with SQL NULL, and the different types of result set.

Methods for Moving the Cursor

MethodDescriptionNeeds a scrollable result set?
next()It is used to move to the next row. Returns false after the last row.No
previous()It moves back one row.Yes
first(), last()They jump to the first or last row.Yes
absolute(n)It jumps to row n (1 is the first).Yes
relative(n)It moves n rows forward, or backward if negative.Yes
beforeFirst(), afterLast()They move outside the rows.Yes
getRow()It returns the current row number.No

Methods for Reading Columns

Every getter comes in two forms: by column label, getInt("marks"), or by position, getInt(3), counting from 1.

SQL typeGetterJava type
INT, SMALLINTgetIntint
BIGINTgetLonglong
DECIMAL, NUMERICgetBigDecimalBigDecimal
DOUBLE, FLOATgetDoubledouble
VARCHAR, CHAR, TEXTgetStringString
BOOLEAN, BITgetBooleanboolean
DATE, TIME, TIMESTAMPgetObject(col, LocalDate.class) and so onLocalDate, LocalTime, LocalDateTime
BLOB, CLOBgetBinaryStream, getCharacterStreamStreams
AnythinggetObjectObject

Types of ResultSet

You choose the type when creating the statement: con.createStatement(type, concurrency).

Type constantCursor movementSees changes made by others?
TYPE_FORWARD_ONLY (default)Forward onlyNot applicable
TYPE_SCROLL_INSENSITIVEAny directionNo
TYPE_SCROLL_SENSITIVEAny directionYes, if the driver supports it
Concurrency constantMeaning
CONCUR_READ_ONLY (default)Rows can only be read
CONCUR_UPDATABLERows can be changed through the result set

Example: Reading, Scrolling and Updating

Results.java▶ Try it
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
 
public class Results {
    public static void main(String[] args) throws Exception {
        try (Connection con =
                 DriverManager.getConnection("jdbc:h2:mem:school")) {
            try (Statement st = con.createStatement()) {
                st.execute("CREATE TABLE student (id INT PRIMARY KEY, "
                    + "name VARCHAR(50), marks INT, city VARCHAR(30))");
                st.executeUpdate("INSERT INTO student VALUES "
                    + "(1, 'Navika', 91, 'Plano'), "
                    + "(2, 'Srihitha', NULL, 'Tirupati'), "
                    + "(3, 'Advitha', 78, NULL)");
            }
 
            // 1. The default ResultSet: forward only, read only.
            try (Statement st = con.createStatement();
                 ResultSet rs = st.executeQuery(
                     "SELECT id, name, marks, city FROM student ORDER BY id")) {
                while (rs.next()) {
                    int marks = rs.getInt("marks");
                    String shown = rs.wasNull() ? "no marks" : marks + "";
                    System.out.println(rs.getInt(1) + " " + rs.getString("name")
                        + " | " + shown + " | " + rs.getString("city"));
                }
            }
 
            // 2. A scrollable ResultSet can move in any direction.
            try (Statement st = con.createStatement(
                     ResultSet.TYPE_SCROLL_INSENSITIVE,
                     ResultSet.CONCUR_READ_ONLY);
                 ResultSet rs = st.executeQuery(
                     "SELECT name FROM student ORDER BY id")) {
                rs.last();
                System.out.println("last:  " + rs.getString(1)
                    + " (row " + rs.getRow() + ")");
                rs.first();
                System.out.println("first: " + rs.getString(1));
                rs.absolute(2);
                System.out.println("row 2: " + rs.getString(1));
                rs.previous();
                System.out.println("back:  " + rs.getString(1));
            }
 
            // 3. An updatable ResultSet can change the table.
            try (Statement st = con.createStatement(
                     ResultSet.TYPE_SCROLL_INSENSITIVE,
                     ResultSet.CONCUR_UPDATABLE);
                 ResultSet rs = st.executeQuery(
                     "SELECT id, name, marks, city FROM student ORDER BY id")) {
                rs.absolute(2);
                rs.updateInt("marks", 84);
                rs.updateRow();
            }
            try (Statement st = con.createStatement();
                 ResultSet rs = st.executeQuery(
                     "SELECT marks FROM student WHERE id = 2")) {
                rs.next();
                System.out.println("Srihitha now has " + rs.getInt(1));
            }
        }
    }
}
Output
1 Navika | 91 | Plano
2 Srihitha | no marks | Tirupati
3 Advitha | 78 | null
last:  Advitha (row 3)
first: Navika
row 2: Srihitha
back:  Navika
Srihitha now has 84

Explanation:

  1. The loop while (rs.next()) is the standard way to read every row. Columns are read by position (getInt(1)) or by label (getString("name")).
  2. NULL and primitives: Srihitha's marks are SQL NULL. getInt can't return null, so it returns 0. Calling rs.wasNull() right after the getter tells you the value was really NULL. For Advitha's city, getString simply returns Java null.
  3. The scrollable result set jumps to the last row, the first, row 2, and back one.
  4. The updatable result set moves to row 2, changes marks with updateInt, and saves it with updateRow(). The last query confirms the table was changed.

Reading NULL Safely

ApproachExample
Check wasNull() after the getterint m = rs.getInt("marks"); if (rs.wasNull()) { ... }
Read as a wrapper objectInteger m = rs.getObject("marks", Integer.class); returns null for NULL

By Label or by Position?

By label: getString("name")By position: getString(2)
ReadabilityClearYou must count columns
If the SELECT list changesStill correctSilently reads the wrong column
SpeedA tiny lookup costFastest

Prefer labels. And list the columns you need in the SELECT, instead of SELECT *, so the result doesn't change when the table does.

Common Mistakes

Reading before calling next(). The cursor isn't on a row yet; the getter throws SQLException.

Using index 0. Columns start at 1.

Trusting getInt for nullable columns. NULL reads as 0.

Calling previous() on a default result set. A forward-only result set throws; ask for a scrollable one.

Returning a ResultSet from a method after closing its connection. It can no longer be read.

Interview Corner

What is a ResultSet and what types are there?

A ResultSet represents the rows returned by a query and maintains a cursor to the current row, initially positioned before the first row. By type: TYPE_FORWARD_ONLY (default, moves only forward), TYPE_SCROLL_INSENSITIVE (scrolls both ways, doesn't reflect later changes by others) and TYPE_SCROLL_SENSITIVE (scrolls and may reflect changes). By concurrency: CONCUR_READ_ONLY (default) and CONCUR_UPDATABLE, which allows updateXxx, updateRow, insertRow and deleteRow.

How do you handle NULL values in a ResultSet?

Getters for primitive types return a default for SQL NULL (0 or false), so call wasNull() immediately after the getter to check whether the last column read was NULL. Alternatively read the column as an object, for example getObject("marks", Integer.class), which returns Java null.

Practice

  1. Easy: Print the students in reverse order using a scrollable result set, afterLast() and previous().
  2. Harder: With an updatable result set, add a new student using moveToInsertRow(), the updateXxx methods and insertRow().

Quick check: ResultSet

4 questions
1Where is the cursor when a ResultSet is first returned?
2What does getInt return for a NULL column?
3Which type lets the cursor move backward?
4What saves a change made with updateInt?

Key Takeaways

Was this tutorial helpful?

Lesson 490 of 578