カーソルが解放されるタイミング

Java + JDBC Thin Driver + Oracle で、カーソルが解放するタイミングを検証してみた。
Statement と ResultSet を close したら、カーソルが解放されると思ってたら、Connection を close しないとカーソルが解放されなかった。こういうもんなんだっけ?検証用のプログラムがおかしいのかな?と思ってたら、

v$open_cursorにはclientでcloseしたカーソルが表示される事があるようです。

# 再利用待ちらしいです

厳密にopen中cursorを調べたい場合は、v$session_cursor_cacheやv$sesstatを
参照すべきでしょう。

    • -

山口@OTNシスオペ

Oracle Technology Network (OTN) Japan - 掲示板 : CallableStatement でカーソルがクローズされない ...

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
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	}
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			}	       		
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	       		}
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	       		}
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