天天看點

mysql怎麼打開遊标的最大數_Java_oracle超出打開遊标的最大數的原因和解決方案...

處理超出打開遊标的最大數異常(ORA-01000: maximum open cursors exceeded)

ORA-01000_maximum_open_cursors_exceeded_

在執行如下代碼時,經常會出現ora-01000: maximum open cursors exceeded異常

1 for(int i=0;i

2 {

3 prepstmt = conn.prepareStatement(sql[i]);

4 prepstmt.setBigDecimal(1,nb.getRealCost());

5 prepstmt.setString(2, adclient_id);

6 prepstmt.setString(3, daystr);

7 prepstmt.setInt(4, ComStatic.portalId);

8 prepstmt.executeUpdate();

9 }

1. 檢查資料庫中的 OPEN_CURSORS 參數值。

1 --Oracle 使用 init.ora 中的初始化參數 OPEN_CURSORS 指定一個會話一次最多可以擁有的遊标數。預設值為 50。要獲得資料庫中 OPEN_CURSORS 參數的值,可以使用以下查詢:

2 SQL> show parameter open_cursors;

3 NAME TYPE VALUE

4 ------------------------------------ ----------- ---------------

5 open_cursors integer 300

6

7 修改open_cursors

8

9 SQL> alter system set open_cursors=1000;

10

11 系統已更改。

12

13 SQL> commit;

14

15 送出完成。

16

17 SQL> show parameter open_cursors;

18

19 NAME TYPE VALUE

20 ------------------------------------ ----------- ---------------------

21 open_cursors integer 1000

22

重要的是将 OPEN_CURSORS 的值設定得足夠大,以避免應用程式用盡所有打開的遊标。應用程式不同,該值也不同。即便會話打開的遊标數未達 OPEN_CURSORS 指定的數量(即設定的值高于實際需要的值),也不會增加系統開銷。

2. 擷取打開的遊标數。

下面的查詢按降序顯示使用者“SCOTT”為每個會話打開的遊标數。

1 SQL> select o.sid, osuser, machine, count(*) num_curs

2 2 from v$open_cursor o, v$session s

3 3 where user_name = 'SCOTT' and o.sid=s.sid

4 4 group by o.sid, osuser, machine

5 5 order by num_curs desc;

6 SID OSUSER MACHINE NUM_CURS

7 -----------------------------------------------------

8 217 m1 1000

9 96 m2 10

10 411 m3 10

11 50 test 9

請注意,v$open_cursor 可以跟蹤會話中 PARSED 和 NOT CLOSED 的動态遊标(使用 dbms_sql.open_cursor() 打開的遊标)。它不會跟蹤未經分析(但已打開)的動态遊标。在應用程式中使用動态遊标并不常見。本模式的前提是未使用動态遊标。

3. 擷取為遊标執行的 SQL。

使用在以上查詢結果中找到的 SID 運作下面的查詢:

1 SQL> select q.sql_text

2 2 from v$open_cursor o, v$sql q

3 3 where q.hash_value=o.hash_value and o.sid = 217;

4 SQL_TEXT

5 select * from empdemo where empid='212'

6 select * from empdemo where empid='321'

7 select * from empdemo where empid='947'

8 select * from empdemo where empid='527'

9 ...

結果将顯示正在連接配接上執行的查詢。它提供了一個入手點,讓您可以反向跟蹤到打開遊标的來源。

這樣的錯誤很容易出現在Java代碼中的主要原因是:Java代碼在執行conn.createStatement()和 conn.prepareStatement()的時候,實際上都是相當與在資料庫中打開了一個cursor。尤其是,如果你的 createStatement和prepareStatement是在一個循環裡面的話,就會非常容易出現這個問題。因為遊标一直在不停的打開,而且沒有關閉。

一般來說,我們在寫Java代碼的時候,createStatement和prepareStatement都應該要放在循環外面,而且使用了這些 Statment後,及時關閉。最好是在執行了一次executeQuery、executeUpdate等之後,如果不需要使用結果集(ResultSet)的資料,就馬上将Statement或PreparedStatement關閉。

對于出現ORA-01000錯誤這種情況,單純的加大open_cursors并不是好辦法,那隻是治标不治本 。 實際上,代碼中的隐患并沒有解除。

而且,絕大部分情況下,open_cursors隻需要設定一個比較小的值,就足夠使用了,除非有非常特别的要求。

如果你不使用連接配接池,那麼就沒有什麼問題,一旦Connection關閉,資料庫實體連接配接就被釋放,所有相關Java資源也可以被GC回收了。

但是如果你使用連接配接池,那麼請注意,Connection關閉并不是實體關閉,隻是歸還連接配接池,是以PreparedStatement和 ResultSet都被持有,并且實際占用相關的資料庫的遊标資源,在這種情況下,隻要長期運作,往往就會報“遊标超出資料庫允許的最大值”的錯誤,導緻程式無法正常通路資料庫。

正确的代碼,如下所示:

1 for(int i=0;i

2 {

3 prepstmt = conn.prepareStatement(sql[i]);

4 prepstmt.setBigDecimal(1,nb.getRealCost());

5 prepstmt.setString(2, adclient_id);

6 prepstmt.setString(3, daystr);

7 prepstmt.setInt(4, ComStatic.portalId);

8 prepstmt.executeUpdate();

9 prepstmt.close();

10 }

在執行了一次executeQuery、executeUpdate等之後,如果不需要使用結果集(ResultSet)的資料,就馬上将Statement或PreparedStatement關閉。