问题 异常ORA-08103:使用Hibernate的setfetchsize时对象不再存在


我正在使用Hibernate。我需要获取大约1000000条记录,这将导致超时异常。所以我正在使用 setfetchsize 对于6000条记录,这样它将在多个事务中分配每条6000条记录的操作。

获取所有内容大约需要21个小时。

但同时检索记录,如果有人删除了要获取的记录之一,那么我得到 ORA-08103: object no longer exists

现在我想跳过检索时删除的那个对象。我怎样才能做到这一点?


11105
2017-09-11 17:29


起源

不知道你要做什么的上下文,但为什么你必须使用hibernate,而不是直接的sql或pl / sql调用。会快得多。 - OldProgrammer
我无法取代Hibernate,因为它会花费更多的时间消耗。我的问题是在执行executeQuery oracle时会抛出ORA-08103:对象不再存在异常,因为有人删除了我使用executeQuery获取的记录。现在我无法阻止任何人在我获取记录的时候删除一行,所以我想要一些技术会导致oracle不为被删除的记录抛出异常而应该跳过该记录继续下一个记录。 - Barney
@Prashant。 。 。为什么要在应用程序中提取一百万行?在我看来,有机会在数据库中进行额外的处理,节省了大量的时间。 - Gordon Linoff


答案:


很可能是基于使用创建的全局临时表(GTT)打开游标 ON COMMIT DELETE ROWS 选项。和事业 ORA-08103: object no longer exists 错误是 commit 紧随其后的声明 delete 声明。这是一个简单的例子:

 SQL> declare
  2    type t_recs is table of number;
  3    l_cur sys_refcursor;    -- our cursor
  4    l_rec t_recs; 
  5  
  6  begin
  7  
  8    -- populating a global temporary table GTT1 with sample data  
  9    insert into GTT1(col)
 10      select level
 11        from dual
 12     connect by level <= 1000;
 13  
 14   open l_cur         -- open a cursor based on data from GTT1
 15    for select col
 16          from GTT1;
 17  
 18    -- here goes delete statement
 19    -- and
 20    commit;  <-- cause of the error. After committing  all data from GTT1 will be
 21              -- deleted and when we try to fetch from the cursor
 22    loop      -- we'll face the ORA-08103 error
 23      fetch l_cur    -- attempt to fetch data which are long gone.
 24       bulk collect into l_rec;
 25      exit when l_cur%notfound;
 26    end loop;
 27  
 28  end;
 29  /


ORA-08103: object no longer exists
ORA-06512: at line 24

使用全局临时表重新创建 on commit preserve rows 子句将允许从基于该表的游标安全地获取数据,而不用担心面对 ORA-08103: 错误。


15
2017-09-11 19:10



你认为还有其他解释吗?我已经开始使用大插件获得此错误(只是一个简单的 insert.. select)从一个视图到一个没有删除发生的表。它的 可能 另一个进程试图截断它下面的表,但应该锁定“原始”表,这将防止这种情况发生。 - Ben
@Ben如果你正在截断一个表 insert select  正在进行的声明,是的,你只会因为得到同样的错误 select statement是一个游标和 truncate 语句,因为它是一个DDL语句,导致双重提交 - 在截断之前,然后在之后。 - Nick Krasnov
啊,当然可以;谢谢尼古拉斯。我将不得不追查那个流氓过程...... - Ben


经过一周的努力,我终于解决了问题:

解决方案:很可能是基于全局临时表(GTT)打开游标,该表是使用ON COMMIT DELETE ROWS选项创建的。并且ORA-08103:对象不再存在的原因错误是紧跟在delete语句之后的commit语句。 DBA团队不同意在提交保留行上更改GTT,所以最后我在Java服务层添加了代码库[实现Spring - Programmatic Transaction]

package com.test;

import java.util.List;
import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class StudentJDBCTemplate implements StudentDAO {
   private DataSource dataSource;
   private JdbcTemplate jdbcTemplateObject;
   private PlatformTransactionManager transactionManager;

   public void setDataSource(DataSource dataSource) {
      this.dataSource = dataSource;
      this.jdbcTemplateObject = new JdbcTemplate(dataSource);
   }
   public void setTransactionManager(PlatformTransactionManager transactionManager) {
      this.transactionManager = transactionManager;
   }
   public void create(String name, Integer age, Integer marks, Integer year){
      TransactionDefinition def = new DefaultTransactionDefinition();
      TransactionStatus status = transactionManager.getTransaction(def);

      try {
         String SQL1 = "insert into Student (name, age) values (?, ?)";
         jdbcTemplateObject.update( SQL1, name, age);

         // Get the latest student id to be used in Marks table
         String SQL2 = "select max(id) from Student";
         int sid = jdbcTemplateObject.queryForInt( SQL2 );

         String SQL3 = "insert into Marks(sid, marks, year) " + "values (?, ?, ?)";
         jdbcTemplateObject.update( SQL3, sid, marks, year);

         System.out.println("Created Name = " + name + ", Age = " + age);
         transactionManager.commit(status);
      } 
      catch (DataAccessException e) {
         System.out.println("Error in creating record, rolling back");
         transactionManager.rollback(status);
         throw e;
      }
      return;
   }
   public List<StudentMarks> listStudents() {
      String SQL = "select * from Student, Marks where Student.id=Marks.sid";
      List <StudentMarks> studentMarks = jdbcTemplateObject.query(SQL, 
         new StudentMarksMapper());

      return studentMarks;
   }
}

0
2017-11-16 20:17