Java + JDBC Thin Driver + Oracle で、カーソルが解放するタイミングを検証してみた。
Statement と ResultSet を close したら、カーソルが解放されると思ってたら、Connection を close しないとカーソルが解放されなかった。こういうもんなんだっけ?検証用のプログラムがおかしいのかな?と思ってたら、
v$open_cursorにはclientでcloseしたカーソルが表示される事があるようです。
# 再利用待ちらしいです
厳密にopen中cursorを調べたい場合は、v$session_cursor_cacheやv$sesstatを
参照すべきでしょう。
- -
山口@OTNシスオペ
OTN Japan - 404 Error
v$open_cursor には close されたカーソルが表示されることがあるらしいので、v$sesstat で確認してみたが、結果は同じだった。どうやら、v$表から正確に open しているカーソルを取得できてないっぽい。
後で、無限ループして select し続けるプログラムを作って検証してみよう。Statement と ResultSet を close したら、永久に動き続け、close しない場合、カーソルリークするはず。たぶん。
以下は検証結果。
- Connection を close するとカーソルは解放される。
$ java Test1
001 scott
SELECT SID, USER_NAME, SQL_TEXT FROM V$OPEN_CURSOR WHERE USER_NAME = 'SCOTT'; no rows selected
select a.sid, a.statistic#,a.value,b.username from v$sesstat a, v$session b where a.statistic# = (select statistic# from v$statname where name = 'opened cursors current') and a.sid = b.sid and b.username = 'SCOTT'; no rows selected
- Statement、ResultSet を close すると、カーソルは解放され
るない。
$ java Test2
001 scott
SELECT SID, USER_NAME, SQL_TEXT FROM V$OPEN_CURSOR WHERE USER_NAME = 'SCOTT'; SID USER_NAME SQL_TEXT ----- -------------------- ------------------------------------------------------------ (中略) 193 SCOTT select id, name from emp 9 rows selected.
select a.sid, a.statistic#,a.value,b.username from v$sesstat a, v$session b where a.statistic# = (select statistic# from v$statname where name = 'opened cursors current') and a.sid = b.sid and b.username = 'SCOTT'; SID STATISTIC# VALUE USERNAME ----- ---------- ---------- ---------- 203 3 1 SCOTT
- Statement だけ close すると、カーソルは解放され
るない。
$ java Test3
001 scott
SELECT SID, USER_NAME, SQL_TEXT FROM V$OPEN_CURSOR WHERE USER_NAME = 'SCOTT'; SID USER_NAME SQL_TEXT ----- -------------------- ------------------------------------------------------------ (中略) 193 SCOTT select id, name from emp 10 rows selected.
select a.sid, a.statistic#,a.value,b.username from v$sesstat a, v$session b where a.statistic# = (select statistic# from v$statname where name = 'opened cursors current') and a.sid = b.sid and b.username = 'SCOTT'; SID STATISTIC# VALUE USERNAME ----- ---------- ---------- ---------- 203 3 1 SCOTT
- ResultSet だけ close すると、カーソルは解放されない。
$ java Test4
001 scott
SELECT SID, USER_NAME, SQL_TEXT FROM V$OPEN_CURSOR WHERE USER_NAME = 'SCOTT'; SID USER_NAME SQL_TEXT ----- -------------------- ------------------------------------------------------------ (中略) 193 SCOTT select id, name from emp 10 rows selected.
select a.sid, a.statistic#,a.value,b.username from v$sesstat a, v$session b where a.statistic# = (select statistic# from v$statname where name = 'opened cursors current') and a.sid = b.sid and b.username = 'SCOTT'; SID STATISTIC# VALUE USERNAME ----- ---------- ---------- ---------- 203 3 1 SCOTT
- Statement、ResultSet を close しないと、カーソルは解放されない。
$ java Test5
001 scott
SELECT SID, USER_NAME, SQL_TEXT FROM V$OPEN_CURSOR WHERE USER_NAME = 'SCOTT'; SID USER_NAME SQL_TEXT ----- -------------------- ------------------------------------------------------------ (中略) 193 SCOTT select id, name from emp 10 rows selected.
select a.sid, a.statistic#,a.value,b.username from v$sesstat a, v$session b where a.statistic# = (select statistic# from v$statname where name = 'opened cursors current') and a.sid = b.sid and b.username = 'SCOTT'; SID STATISTIC# VALUE USERNAME ----- ---------- ---------- ---------- 203 3 1 SCOTT
- Test1.java
1 import java.sql.Connection; 2 import java.sql.DriverManager; 3 import java.sql.Statement; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 public class Test1 { 7 public static void main(String args[]) { 8 Connection conn = null; 9 Statement stmt = null; 10 ResultSet resultSet = null; 11 try { 12 Class.forName ("oracle.jdbc.driver.OracleDriver"); 13 conn = DriverManager.getConnection 14 ("jdbc:oracle:thin:@192.168.45.101:1521:orcl","scott","tiger"); 15 stmt = conn.createStatement(); 16 resultSet = stmt.executeQuery("select id, name from emp"); 17 for(;resultSet.next();) { 18 System.out.println(resultSet.getString(1) + " " + resultSet.getString(2)); 19 } 20 } catch (SQLException e) { 21 System.out.println("Error code: " + e.getErrorCode()); 22 System.out.println("SQL state: " + e.getSQLState()); 23 e.printStackTrace(); 24 } catch (ClassNotFoundException e) { 25 e.printStackTrace(); 26 } finally { 27 /* 28 try { 29 if (resultSet != null) { 30 resultSet.close(); 31 } 32 } catch (SQLException e){ 33 e.printStackTrace(); 34 } 35 try { 36 if (stmt != null) { 37 stmt.close(); 38 } 39 } catch (SQLException e){ 40 e.printStackTrace(); 41 } 42 */ 43 try { 44 if (conn != null) { 45 conn.close(); 46 } 47 } catch (SQLException e){ 48 e.printStackTrace(); 49 } 50 } 51 try { 52 Thread.sleep(600000); 53 } catch (InterruptedException e) { 54 e.printStackTrace(); 55 } 56 } 57 }
- Test2.java
26 } finally { 27 try { 28 if (resultSet != null) { 29 resultSet.close(); 30 } 31 } catch (SQLException e){ 32 e.printStackTrace(); 33 } 34 try { 35 if (stmt != null) { 36 stmt.close(); 37 } 38 } catch (SQLException e){ 39 e.printStackTrace(); 40 } 41 /* 42 try { 43 if (conn != null) { 44 conn.close(); 45 } 46 } catch (SQLException e){ 47 e.printStackTrace(); 48 } 49 */ 50 }
- Test3.java
26 } finally { 27 /* 28 try { 29 if (resultSet != null) { 30 resultSet.close(); 31 } 32 } catch (SQLException e){ 33 e.printStackTrace(); 34 } 35 */ 36 try { 37 if (stmt != null) { 38 stmt.close(); 39 } 40 } catch (SQLException e){ 41 e.printStackTrace(); 42 } 43 /* 44 try { 45 if (conn != null) { 46 conn.close(); 47 } 48 } catch (SQLException e){ 49 e.printStackTrace(); 50 } 51 */ 52 }
- Test4.java
26 } finally { 27 try { 28 if (resultSet != null) { 29 resultSet.close(); 30 } 31 } catch (SQLException e){ 32 e.printStackTrace(); 33 } 34 /* 35 try { 36 if (stmt != null) { 37 stmt.close(); 38 } 39 } catch (SQLException e){ 40 e.printStackTrace(); 41 } 42 try { 43 if (conn != null) { 44 conn.close(); 45 } 46 } catch (SQLException e){ 47 e.printStackTrace(); 48 } 49 */ 50 }
- Test5.java
26 } finally { 27 /* 28 try { 29 if (resultSet != null) { 30 resultSet.close(); 31 } 32 } catch (SQLException e){ 33 e.printStackTrace(); 34 } 35 try { 36 if (stmt != null) { 37 stmt.close(); 38 } 39 } catch (SQLException e){ 40 e.printStackTrace(); 41 } 42 try { 43 if (conn != null) { 44 conn.close(); 45 } 46 } catch (SQLException e){ 47 e.printStackTrace(); 48 } 49 */ 50 }
[参考]
[Oracle] ORA-01000エラーの回避方法 | Archive Redo Blog
[Oracle] ORA-01000エラーの原因特定のためにV$OPEN_CURSORを利用する | Archive Redo Blog
トラブルシューティング
SQL
Welcome | Oracle Community
ORA-1000 max open cursor (JDBC Thin) | Oracle Community
http://otndnld.oracle.co.jp/document/products/oracle11g/111/doc_dvd/server.111/E05771-03/initparams.htm#93802