Перейти к основному содержимому

Получить количество строк в наборе результатов

· 4 мин. чтения

1. Обзор

В этой статье мы рассмотрим различные способы подсчета количества строк JDBC ResultSet .

2. Подсчет строк набора результатов

Подсчет строк ResultSet не является простым, поскольку ни один метод API не предоставляет эту информацию. Причина этого в том, что запрос JDBC не сразу извлекает все результаты . Результаты строки загружаются из базы данных каждый раз, когда мы запрашиваем их с помощью метода ResultSet.next .

Когда мы выполняем запрос JDBC, мы не можем заранее знать, сколько результатов мы получим. Вместо этого нам нужно пройти их все, и только когда мы дойдем до конца, мы сможем быть уверены в количестве доступных строк.

Мы можем сделать это двумя способами: используя стандартный или прокручиваемый ResultSet .

3. Стандартный набор результатов

Самый простой способ подсчета результатов нашего запроса — перебрать их все и увеличить переменную счетчика для каждого результата.

Давайте создадим класс StandardRowCounter с одним параметром для подключения к базе данных:

class StandardRowCounter {
Connection conn;

StandardRowCounter(Connection conn) {
this.conn = conn;
}
}

Наш класс будет содержать единственный метод, который примет SQL-запрос как строку и вернет количество строк, перебирая ResultSet , увеличивая переменную счетчика для каждого результата.

Назовем наш метод счетчика getQueryRowCount :

int getQueryRowCount(String query) throws SQLException {
try (Statement statement = conn.createStatement();
ResultSet standardRS = statement.executeQuery(query)) {
int size = 0;
while (standardRS.next()) {
size++;
}
return size;
}
}

Обратите внимание, что мы используем блок try-with-resources для автоматического закрытия ресурсов JDBC.

Чтобы протестировать нашу реализацию, мы воспользуемся преимуществами базы данных в памяти , чтобы быстро сгенерировать таблицу с 3 записями.

Имея это в виду, давайте создадим RowCounterApp с помощью простого основного метода:

class RowCounterApp {

public static void main(String[] args) throws SQLException {
Connection conn = createDummyDB();

String selectQuery = "SELECT * FROM STORAGE";

StandardRowCounter standardCounter = new StandardRowCounter(conn);
assert standardCounter.getQueryRowCount(selectQuery) == 3;
}

static Connection createDummyDB() throws SQLException {
...
}

}

Описанный выше метод будет работать в любой базе данных . Однако, если драйвер базы данных поддерживает это, есть более продвинутые API, которые мы можем использовать для достижения того же результата.

4. Прокручиваемый набор результатов

Используя перегруженный метод Statement createStatement, мы можем запросить создание прокручиваемого ResultSet после выполнения запроса. С прокручиваемой версией мы можем использовать более продвинутые методы обхода, такие как предыдущие , для перемещения назад. В нашем случае мы перейдем к концу набора результатов , используя последний метод, и получим номер строки последней записи, которая задается методом getRow . ``

Давайте создадим класс ScrollableRowCounter :

class ScrollableRowCounter {
Connection conn;

ScrollableRowCounter(Connection conn) {
this.conn = conn;
}
}

Как и в случае с нашим StandardRowCounter , единственное поле, которое мы будем использовать, — это поле Connection Connection .

Опять же, мы будем использовать метод getQueryRowCount :

int getQueryRowCount(String query) throws SQLException {
try (Statement statement = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet scrollableRS = statement.executeQuery(query)) {
scrollableRS.last();
return scrollableRS.getRow();
}
}

Чтобы получить прокручиваемый набор результатов , мы должны предоставить константу ResultSet.TYPE_SCROLL_INSENSITIVE методу createStatement . Кроме того, мы должны указать значение для режима параллелизма, но поскольку это не имеет отношения к нашему случаю, мы используем ResultSet по умолчанию. Константа CONCUR_READ_ONLY. В случае, если драйвер JDBC не поддерживает этот режим работы, он выдаст исключение.

Давайте протестируем нашу новую реализацию с помощью RowCountApp :

ScrollableRowCounter scrollableCounter = new ScrollableRowCounter(conn);
assert scrollableCounter.getQueryRowCount(selectQuery) == 3;

5. Вопросы производительности

Хотя приведенные выше реализации просты, они не обеспечивают наилучшей производительности из-за обязательного обхода ResultSet . По этой причине обычно рекомендуется использовать запрос типа COUNT для операций подсчета строк.

Простой пример:

SELECT COUNT(*) FROM STORAGE

Это возвращает одну строку с одним столбцом, который содержит количество строк в таблице STORAGE .

6. Заключение

В этой статье мы рассмотрели различные способы получения количества строк в ResultSet .

Как всегда, исходный код этой статьи доступен на GitHub .