JDBC ResultSet с MySQL игнорирует тип ResultSet

Я пытаюсь обработать большой объем данных в приложении Java. Данные хранятся в базе данных MySQL, и я использую соединитель jdbc 8.0.11.

Моя проблема в том, что мне нужно обращаться к каждой записи несколько раз, а повторное выполнение запроса занимает слишком много времени. Использование ResultSet.absolute(1) вызывает исключение, объясняющее, что курсор - TYPE_FORWARD_ONLY.

Как описано здесь, оператор должен быть создан с параметрами ResultSet.TYPE_SCROLL_INSENSITIVE и параметром ResultSet.CONCUR_READ_ONLY, чтобы получить набор результатов с возможностью прокрутки.

Но мой созданный ResultSet всегда является ResultSet.TYPE_FORWARD_ONLY, игнорируя любые параметры, предоставленные в методе оператора create.

В официальном Сайт MySQL я не нашел ни объяснений, ни информации, поддерживается ли эта функция.

Для тестового случая я написал этот код, чтобы проверить, не повлияет ли какая-либо другая комбинация на тип ResultSet, и всегда получал TYPE_FORWARD_ONLY.

Connection conn = Database.getConnection();
    Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll sensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll insensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll insensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll sensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll sensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE,ResultSet.HOLD_CURSORS_OVER_COMMIT);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll insensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY,ResultSet.HOLD_CURSORS_OVER_COMMIT);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll insensitive, is forward only");
    }
    st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE,ResultSet.HOLD_CURSORS_OVER_COMMIT);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll sensitive, is forward only");
    }       
    st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY,ResultSet.HOLD_CURSORS_OVER_COMMIT);
    if (st.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) {
        System.out.println("Should be scroll sensitive, is forward only");
    }

Вот фрагмент кода, объясняющий, как я создаю соединение с базой данных:

private static final String driverName = "com.mysql.cj.jdbc.Driver";

    com.mysql.cj.jdbc.Driver dr = (com.mysql.cj.jdbc.Driver) Class.forName(driverName).newInstance();

    MysqlDataSource src = new MysqlDataSource();
    src.setUseCursorFetch(true);        
    src.setServerName("localhost");     
    src.setPort(port);
    src.setDatabaseName("dbname");
    src.setUseSSL(false);
    src.setUser(dbUser);
    src.setPassword(dbPass);
    src.setServerTimezone("GMT+2");
    conn = src.getConnection(dbUser, dbPass);

Поэтому я хотел бы спросить:

  1. Почему мой ResultSet всегда TYPE_FORWARD_ONLY?
  2. Есть ли способ изменить это поведение?

Драйверам JDBC разрешено понизить тип набора результатов, если они не могут выполнить запрос. Однако у меня создалось впечатление, что MySQL Connector / J действительно поддерживает (или, по крайней мере, моделирует) прокручиваемые курсоры. Интересно, изменили ли они это в версии 8.

Mark Rotteveel 09.05.2018 18:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
1
922
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

JDBC ResultSet семантически похож на курсор базы данных, но не все системы баз данных, включая MySQL, поддерживают курсоры (см. Ниже). Если реализованы TYPE_SCROLL_SENSITIVE или TYPE_SCROLL_INSENSITIVE, это обычно означает, что драйвер JDBC нацелен на базу данных, поддерживающую прокручиваемые курсоры. Конечно, драйвер JDBC все еще может быть написан для имитации этого поведения путем кэширования набора результатов, но большинство драйверов этого не делают.

Из документации MySQL ((src: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html)

MySQL does not support SQL cursors, and the JDBC driver does not emulate them, so setCursorName() has no effect.

Новые версии MySQL частично поддерживают курсоры (http://www.mysqltutorial.org/mysql-cursor/), но они по-прежнему не прокручиваются.

Итак, чтобы делать то, что вы хотите, просто кешируйте набор результатов (например, сохраните его в хэш-карте или другом контейнере) и извлекайте конкретную запись, когда она вам нужна.

Другие вопросы по теме