Рекурсивное использование ROWNUM с транзакционным методом

1

У меня есть таблица с именем Person, мой select sql обычно приносит количество разрешений, скажем, 100K человек, так как у меня так много времени, когда я получаю исключение для чтения. Поэтому я знаю, что я должен использовать ROWNUM для ограничения размера результата.

Class MyService {
  @Transactional(rollbackFor = Exception.class)
doJob(){

  jobService.process();
}

}

Class JobService {
    public void process() {
    List<Person> personlList= jdbcQuery.query ("Select * from ... ... where rownum<1000" , ROWMAPPAR, parameter);
//Process all record list
    }

Все в порядке до тех пор, пока не будет известно. Но я хочу быть уверенным, что вся запись позволяет говорить, что 100K обрабатывается, и, если есть ошибка при обработке одной из партий, должен произойти откат.

Нужно ли мне возвращать метод process() рекурсивно?

Использование Spring 3.5 Oracle 11g

Теги:
spring

2 ответа

1
Лучший ответ

Использование ROWNUM, как показано в вашем запросе, может очень не дать вам ожидаемых результатов. (Но, с другой стороны, это возможно, по крайней мере иногда :-). ROWNUM генерируется по мере того, как строки испускаются из запроса, ПОСЛЕ определения предложения WHERE, но ПЕРЕД какими-либо предложениями ORDER BY или HAVING. Это может привести к тому, что ваш запрос вернет результаты, которые могут вас удивить.

Попробуйте создать следующую таблицу:

create table t(n number);

И заселение его:

insert into t (n)
  select n from
   (select rownum n from dual connect by level <= 2000)
   where n > 1234;

Таким образом, таблица будет иметь строки со значениями от 1235 до 2000.

Запустите каждый из следующих запросов в следующем порядке:

select *
  from t
  order by n;

select n, rownum
  from t
  where rownum < 100
  order by n;

select n, rownum as r from
 (select n
    from t
    order by n);

select n, r from
 (select n, rownum as r from
   (select n
      from t
      order by n))
  where r < 100
  order by n;

и наблюдайте различия в выходе, который вы получаете.

Для тех, у кого нет экземпляра Oracle, здесь SQLFiddle с указанным выше.

Поделитесь и наслаждайтесь.

  • 0
    Это все верно, конечно, но я думаю, что (даже если это будет принято), это не настоящая проблема ОП ... Они спрашивают, как сохранить каждую подзадачу пакета в одной транзакции на стороне клиента.
  • 0
    Я установил fetchsize jdbctemplate.setFetchSize () и удалил оператор ROWNUM. Я думал, что jdbctemplate получает размер записи по fetchsize, пока все записи не будут приняты
1

Нужно ли мне возвращать метод process() рекурсивно?

Я бы этого не сделал. Просто перепишите свой код на это:

class MyService {

  @Transactional(rollbackFor = Exception.class)
  void doJob(){

    // Continue processing within the same transaction, until process() returns false
    while (jobService.process());
  }
}

class JobService {
  public boolean process() {
    List<Person> personlList= jdbcQuery.query(
      "Select * from ... ... where rownum<=1000" , ROWMAPPAR, parameter);
    // I've changed your predicate ------^^

    // process() returns false when the above select returns less than 1000 records
    return personList.size() == 1000;
  }
}

Остерегайтесь, однако, что одна из проблем, которые вы испытываете, заключается в том, что вы сохраняете очень длительную транзакцию. Это вызовет много параллелизма внутри вашей базы данных и может способствовать медленному выполнению пакетного задания. Если вам не требуется абсолютно атомное пакетное задание (все исправлено или все откат), вы можете рассмотреть возможность запуска каждого подзадания в своей собственной транзакции.

  • 0
    Я установил fetchsize jdbctemplate.setFetchSize () и удалил оператор ROWNUM. Я думал, что jdbctemplate получает размер выборки за счет fetchsize, пока все записи не будут приняты
  • 0
    Как насчет последних записей, чтобы не сказать последние 800 записей? На основании вашего примера эти записи не будут правильно обработаны
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню