私はHibernateを使用しています。約1000000レコードをフェッチする必要があり、タイムアウト例外が発生します。したがって、6000レコードに対してsetfetchsize
を使用しているため、操作は6000レコードごとに複数のトランザクションに分散されます。
すべてを取得するには、約21時間かかります。
しかし、その間にレコードを取得するときに、フェッチされたレコードの1つを誰かが削除した場合、ORA-08103: object no longer exists
。
次に、取得中に削除されたオブジェクトをスキップします。これどうやってするの?
カーソルは、ON COMMIT DELETE ROWS
オプションで作成されたグローバル一時テーブル(GTT)に基づいて開かれる可能性が高いです。そして、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:
エラーに直面することを恐れずに、そのテーブルに基づくカーソルからデータを安全にフェッチできます。
1週間苦労した後、ようやく問題を修正しました。
解決策:ほとんどの場合、ON COMMIT DELETE ROWSオプションを使用して作成されたグローバル一時テーブル(GTT)に基づいてカーソルが開かれます。また、ORA-08103:オブジェクトが存在しないエラーの原因は、削除ステートメントの直後に続くコミットステートメントです。 DBAチームはコミット保持行のようにGTTを変更することに同意しなかったため、最後にコードベースをJava Service Layer [Implementing 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;
}
}