使用事务方法递归ROWNUM用法

时间:2014-12-27 18:28:53

标签: java spring oracle

我有一个名为Person的表,我的选择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()方法?

是 春天3.5 Oracle 11g

2 个答案:

答案 0 :(得分:1)

如您的查询中所示使用ROWNUM可能无法提供您期望的结果。 (但另一方面它可能,至少有时候:-)。从查询中发出行时生成ROWNUM, AFTER 评估WHERE子句,但 BEFORE 应用任何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实例的人,here's an SQLFiddle with the above in it

分享并享受。

答案 1 :(得分: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;
  }
}
但是,请注意,您可能遇到的一个问题是,您正在保持一个非常长时间运行的事务。这将导致数据库内部出现大量并发,并可能导致批处理作业运行缓慢。如果您不是绝对需要原子批处理作业(已提交的所有内容或所有已回滚的内容),您可以考虑在自己的事务中运行每个子作业。