Как реализовать отложенную выборку данных БД с использованием spring

#java #spring #spring-data #lazy-loading #junit4

#java #spring #spring-данные #отложенная загрузка #junit4

Вопрос:

Прежде чем описать свою проблему, я хочу сообщить вам, что я новичок в Spring.

Итак, здесь я просто помещаю свой пример кода, что я делаю для извлечения данных из БД с помощью JdbcTemplate :

     SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
    dataSource.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
    dataSource.setUrl("jdbc:derby:C:/Users/mypc/Downloads/db-derby-10.12.1.1-bin/db-derby-10.12.1.1-bin/demo/databases/toursdb;create=true");
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    List<Map<String, Object>> rows = jdbcTemplate.queryForList("select * from "   tableName);
    dataSource.getConnection().close();
    System.out.println(rows);
  

Итак, здесь я помещаю весь свой результирующий набор в Map, а затем возвращаю его. Проблема в том, что она создает исключение из памяти кучи java для большого набора данных (как я упоминал выше, опубликованный код предназначен для примера).

Теперь я изменяю эту реализацию, используя RowCallbackHandler().

Итак, мой измененный код теперь

             SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
            dataSource.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
            dataSource.setUrl("jdbc:derby:C:/Users/mypc/Downloads/db-derby-10.12.1.1-bin/db-derby-10.12.1.1-bin/demo/databases/toursdb;create=true");
            JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
            jdbcTemplate.setFetchSize(200);
            jdbcTemplate.query("select * from "   tableName, new RowCallbackHandler() {
                public void processRow(ResultSet rs) throws SQLException {
                    Map<String, Object> rowInMap = new HashMap<String, Object>();
                    for (int i = 1; i <= rs.getMetaData().getColumnCount(); i  ) {
                        rowInMap.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
                    }
                    System.out.println(rowInMap);
                }
            });
            dataSource.getConnection().close();
  

Но проблема в том, как использовать метод rowcallbackhandler из другого метода из другого класса, который будет лениво использовать данные, и, очевидно, он должен быть потокобезопасным. Он будет использоваться для тестирования JUnit.

Комментарии:

1. consume data lazily Я не думаю, что это означает то, что вы думаете. То, что вы, кажется, хотите, — это пакетирование, то есть потребляющий код извлекает данные пакетами некоторого фиксированного размера (например, 20, 50, 100 что угодно) и обрабатывает их порциями.

2. да, точно, я хочу заполнить свою карту 20 данными, а затем обработать ее снова, чтобы восстановить часть набора результатов, и она заполнит карту следующими 20 данными

3. Я еще раз говорю, посмотрите на пакетную обработку с помощью шаблонов jdbc

4. Я изучаю это, но замечаю, что оно используется для обновления. мое требование — получение данных из БД, а не обновление БД.

5. разбиение на страницы может быть термином с большим количеством просмотров в Google.

Ответ №1:

Вы указываете драйверу jdbc извлекать строки по 200 и 200. Вот объяснение java-документа Statement class.

 /**
     * Gives the JDBC driver a hint as to the number of rows that should
     * be fetched from the database when more rows are needed for
     * <code>ResultSet</code> objects genrated by this <code>Statement</code>.
     * If the value specified is zero, then the hint is ignored.
     * The default value is zero.
     *
     * @param rows the number of rows to fetch
     * @exception SQLException if a database access error occurs,
     * this method is called on a closed <code>Statement</code> or the
     *        condition  <code>rows >= 0</code> is not satisfied.
     * @since 1.2
     * @see #getFetchSize
     */
  

Вы не указываете отложенную загрузку или фильтрацию в своем запросе, вы извлекаете всю таблицу. Самый простой способ — использовать условие where для фильтрации ваших записей или использовать функцию разбивки на страницы.
Для oracle вы можете добавить «where rownum < 200» к вашему запросу.
Spring jdbc основан на выборке записей, сборе внутри коллекции и возврате. Поэтому, когда вы получаете свой список, это означает, что все данные извлекаются из базы данных, а оператор закрывается. Вы можете обработать свою запись внутри класса RowCallbackHandler, однако во время вашего процесса оператор базы данных и набор результатов будут открыты.

Комментарии:

1. Согласно вашему предложению, если я добавлю rownum для oracle или top для sql server, я не смогу получить все данные, но мне нужны все данные для проверки с моим ожидаемым.

2. итак, вам нужно отфильтровать свои данные с помощью предложения where в вашем sql. Кроме того, oracle rownum не гарантирует получение одних и тех же данных каждый раз.

3. Спасибо за ваши комментарии, но есть ли какой-либо способ вернуть фрагмент карты и проверить это, и если не найден желаемый результат, снова вызовите его и верните следующий фрагмент карты из того же результирующего набора, это похоже на возврат.