在執(zhí)行如下代碼時(shí),經(jīng)常會(huì)出現(xiàn)ora-01000: maximum open cursors exceeded異常
for(int i=0;i<balancelist.size();i++)
{
???? prepstmt = conn.prepareStatement(sql[i]);
???? prepstmt.setBigDecimal(1,nb.getRealCost());
???? prepstmt.setString(2, adclient_id);
???? prepstmt.setString(3, daystr);
???? prepstmt.setInt(4, ComStatic.portalId);
???? prepstmt.executeUpdate();
}
1. 檢查數(shù)據(jù)庫(kù)中的 OPEN_CURSORS 參數(shù)值。
Oracle 使用 init.ora 中的初始化參數(shù) OPEN_CURSORS 指定一個(gè)會(huì)話一次最多可以擁有的游標(biāo)數(shù)。缺省值為 50。要獲得數(shù)據(jù)庫(kù)中 OPEN_CURSORS 參數(shù)的值,可以使用以下查詢:???
SQL> show parameter open_cursors;
NAME????????????????????????????????? TYPE???????? VALUE
------------------------------------ ----------- ---------------
open_cursors????????????????????????? integer????? 1000???
重要的是將 OPEN_CURSORS 的值設(shè)置得足夠大,以避免應(yīng)用程序用盡所有打開(kāi)的游標(biāo)。應(yīng)用程序不同,該值也不同。即便會(huì)話打開(kāi)的游標(biāo)數(shù)未達(dá) OPEN_CURSORS 指定的數(shù)量(即設(shè)置的值高于實(shí)際需要的值),也不會(huì)增加系統(tǒng)開(kāi)銷。
2. 獲取打開(kāi)的游標(biāo)數(shù)。
下面的查詢按降序顯示用戶“SCOTT”為每個(gè)會(huì)話打開(kāi)的游標(biāo)數(shù)。??
SQL> select o.sid, osuser, machine, count(*) num_curs
?? 2?? from v$open_cursor o, v$session s
?? 3?? where user_name = 'SCOTT' and o.sid=s.sid
?? 4?? group by o.sid, osuser, machine
?? 5 order by?? num_curs desc;
??? SID OSUSER??????? MACHINE??????????? NUM_CURS
-----------------------------------------------------
??????? 217??????????? m1???????????????? 1000
???????? 96??????????? m2???????????????? 10
??????? 411??????????? m3???????????????? 10
???????? 50?????????? test???????????????? 9
請(qǐng)注意,v$open_cursor 可以跟蹤會(huì)話中 PARSED 和 NOT CLOSED 的動(dòng)態(tài)游標(biāo)(使用 dbms_sql.open_cursor() 打開(kāi)的游標(biāo))。它不會(huì)跟蹤未經(jīng)分析(但已打開(kāi))的動(dòng)態(tài)游標(biāo)。在應(yīng)用程序中使用動(dòng)態(tài)游標(biāo)并不常見(jiàn)。本模式的前提是未使用動(dòng)態(tài)游標(biāo)。
3. 獲取為游標(biāo)執(zhí)行的 SQL。
使用在以上查詢結(jié)果中找到的 SID 運(yùn)行下面的查詢:
SQL> select q.sql_text
?? 2?? from v$open_cursor o, v$sql q
?? 3?? where q.hash_value=o.hash_value and o.sid = 217;
SQL_TEXT
select * from empdemo where empid='212'
select * from empdemo where empid='321'
select * from empdemo where empid='947'
select * from empdemo where empid='527'
...
結(jié)果將顯示正在連接上執(zhí)行的查詢。它提供了一個(gè)入手點(diǎn),讓您可以反向跟蹤到打開(kāi)游標(biāo)的來(lái)源。
這樣的錯(cuò)誤很容易出現(xiàn)在Java代碼中的主要原因是:Java代碼在執(zhí)行conn.createStatement()和 conn.prepareStatement()的時(shí)候,實(shí)際上都是相當(dāng)與在數(shù)據(jù)庫(kù)中打開(kāi)了一個(gè)cursor。尤其是,如果你的 createStatement和prepareStatement是在一個(gè)循環(huán)里面的話,就會(huì)非常容易出現(xiàn)這個(gè)問(wèn)題。因?yàn)橛螛?biāo)一直在不停的打開(kāi),而且沒(méi) 有關(guān)閉。
一般來(lái)說(shuō),我們?cè)趯?xiě)Java代碼的時(shí)候,createStatement和prepareStatement都應(yīng)該要放在循環(huán)外面,而且使用了這些 Statment后,及時(shí)關(guān)閉。最好是在執(zhí)行了一次executeQuery、executeUpdate等之后,如果不需要使用結(jié)果集 (ResultSet)的數(shù)據(jù),就馬上將Statement或PreparedStatement關(guān)閉。
對(duì)于出現(xiàn)ORA-01000錯(cuò)誤這種情況,單純的加大open_cursors并不是好辦法,那只是治標(biāo)不治本。實(shí)際上,代碼中的隱患并沒(méi)有解除。
而且,絕大部分情況下,open_cursors只需要設(shè)置一個(gè)比較小的值,就足夠使用了,除非有非常特別的要求。
???? 如果你不使用連接池,那么就沒(méi)有什么問(wèn)題,一旦Connection關(guān)閉,數(shù)據(jù)庫(kù)物理連接就被釋放,所有相關(guān)Java資源也可以被GC回收了。
但是如果你使用連接池,那么請(qǐng)注意,Connection關(guān)閉并不是物理關(guān)閉,只是歸還連接池,所以PreparedStatement和 ResultSet都被持有,并且實(shí)際占用相關(guān)的數(shù)據(jù)庫(kù)的游標(biāo)資源,在這種情況下,只要長(zhǎng)期運(yùn)行,往往就會(huì)報(bào)“游標(biāo)超出數(shù)據(jù)庫(kù)允許的最大值”的錯(cuò)誤,導(dǎo)致 程序無(wú)法正常訪問(wèn)數(shù)據(jù)庫(kù)。
正確的代碼,如下所示:
for(int i=0;i<balancelist.size();i++)
{
???? prepstmt = conn.prepareStatement(sql[i]);
???? prepstmt.setBigDecimal(1,nb.getRealCost());
???? prepstmt.setString(2, adclient_id);
???? prepstmt.setString(3, daystr);
???? prepstmt.setInt(4, ComStatic.portalId);
???? prepstmt.executeUpdate();
?? prepstmt.close();
}
在執(zhí)行了一次executeQuery、executeUpdate等之后,如果不需要使用結(jié)果集(ResultSet)的數(shù)據(jù),就馬上將Statement或PreparedStatement關(guān)閉。
for(int i=0;i<balancelist.size();i++)
{
???? prepstmt = conn.prepareStatement(sql[i]);
???? prepstmt.setBigDecimal(1,nb.getRealCost());
???? prepstmt.setString(2, adclient_id);
???? prepstmt.setString(3, daystr);
???? prepstmt.setInt(4, ComStatic.portalId);
???? prepstmt.executeUpdate();
}
1. 檢查數(shù)據(jù)庫(kù)中的 OPEN_CURSORS 參數(shù)值。
Oracle 使用 init.ora 中的初始化參數(shù) OPEN_CURSORS 指定一個(gè)會(huì)話一次最多可以擁有的游標(biāo)數(shù)。缺省值為 50。要獲得數(shù)據(jù)庫(kù)中 OPEN_CURSORS 參數(shù)的值,可以使用以下查詢:???
SQL> show parameter open_cursors;
NAME????????????????????????????????? TYPE???????? VALUE
------------------------------------ ----------- ---------------
open_cursors????????????????????????? integer????? 1000???
重要的是將 OPEN_CURSORS 的值設(shè)置得足夠大,以避免應(yīng)用程序用盡所有打開(kāi)的游標(biāo)。應(yīng)用程序不同,該值也不同。即便會(huì)話打開(kāi)的游標(biāo)數(shù)未達(dá) OPEN_CURSORS 指定的數(shù)量(即設(shè)置的值高于實(shí)際需要的值),也不會(huì)增加系統(tǒng)開(kāi)銷。
2. 獲取打開(kāi)的游標(biāo)數(shù)。
下面的查詢按降序顯示用戶“SCOTT”為每個(gè)會(huì)話打開(kāi)的游標(biāo)數(shù)。??
SQL> select o.sid, osuser, machine, count(*) num_curs
?? 2?? from v$open_cursor o, v$session s
?? 3?? where user_name = 'SCOTT' and o.sid=s.sid
?? 4?? group by o.sid, osuser, machine
?? 5 order by?? num_curs desc;
??? SID OSUSER??????? MACHINE??????????? NUM_CURS
-----------------------------------------------------
??????? 217??????????? m1???????????????? 1000
???????? 96??????????? m2???????????????? 10
??????? 411??????????? m3???????????????? 10
???????? 50?????????? test???????????????? 9
請(qǐng)注意,v$open_cursor 可以跟蹤會(huì)話中 PARSED 和 NOT CLOSED 的動(dòng)態(tài)游標(biāo)(使用 dbms_sql.open_cursor() 打開(kāi)的游標(biāo))。它不會(huì)跟蹤未經(jīng)分析(但已打開(kāi))的動(dòng)態(tài)游標(biāo)。在應(yīng)用程序中使用動(dòng)態(tài)游標(biāo)并不常見(jiàn)。本模式的前提是未使用動(dòng)態(tài)游標(biāo)。
3. 獲取為游標(biāo)執(zhí)行的 SQL。
使用在以上查詢結(jié)果中找到的 SID 運(yùn)行下面的查詢:
SQL> select q.sql_text
?? 2?? from v$open_cursor o, v$sql q
?? 3?? where q.hash_value=o.hash_value and o.sid = 217;
SQL_TEXT
select * from empdemo where empid='212'
select * from empdemo where empid='321'
select * from empdemo where empid='947'
select * from empdemo where empid='527'
...
結(jié)果將顯示正在連接上執(zhí)行的查詢。它提供了一個(gè)入手點(diǎn),讓您可以反向跟蹤到打開(kāi)游標(biāo)的來(lái)源。
這樣的錯(cuò)誤很容易出現(xiàn)在Java代碼中的主要原因是:Java代碼在執(zhí)行conn.createStatement()和 conn.prepareStatement()的時(shí)候,實(shí)際上都是相當(dāng)與在數(shù)據(jù)庫(kù)中打開(kāi)了一個(gè)cursor。尤其是,如果你的 createStatement和prepareStatement是在一個(gè)循環(huán)里面的話,就會(huì)非常容易出現(xiàn)這個(gè)問(wèn)題。因?yàn)橛螛?biāo)一直在不停的打開(kāi),而且沒(méi) 有關(guān)閉。
一般來(lái)說(shuō),我們?cè)趯?xiě)Java代碼的時(shí)候,createStatement和prepareStatement都應(yīng)該要放在循環(huán)外面,而且使用了這些 Statment后,及時(shí)關(guān)閉。最好是在執(zhí)行了一次executeQuery、executeUpdate等之后,如果不需要使用結(jié)果集 (ResultSet)的數(shù)據(jù),就馬上將Statement或PreparedStatement關(guān)閉。
對(duì)于出現(xiàn)ORA-01000錯(cuò)誤這種情況,單純的加大open_cursors并不是好辦法,那只是治標(biāo)不治本。實(shí)際上,代碼中的隱患并沒(méi)有解除。
而且,絕大部分情況下,open_cursors只需要設(shè)置一個(gè)比較小的值,就足夠使用了,除非有非常特別的要求。
???? 如果你不使用連接池,那么就沒(méi)有什么問(wèn)題,一旦Connection關(guān)閉,數(shù)據(jù)庫(kù)物理連接就被釋放,所有相關(guān)Java資源也可以被GC回收了。
但是如果你使用連接池,那么請(qǐng)注意,Connection關(guān)閉并不是物理關(guān)閉,只是歸還連接池,所以PreparedStatement和 ResultSet都被持有,并且實(shí)際占用相關(guān)的數(shù)據(jù)庫(kù)的游標(biāo)資源,在這種情況下,只要長(zhǎng)期運(yùn)行,往往就會(huì)報(bào)“游標(biāo)超出數(shù)據(jù)庫(kù)允許的最大值”的錯(cuò)誤,導(dǎo)致 程序無(wú)法正常訪問(wèn)數(shù)據(jù)庫(kù)。
正確的代碼,如下所示:
for(int i=0;i<balancelist.size();i++)
{
???? prepstmt = conn.prepareStatement(sql[i]);
???? prepstmt.setBigDecimal(1,nb.getRealCost());
???? prepstmt.setString(2, adclient_id);
???? prepstmt.setString(3, daystr);
???? prepstmt.setInt(4, ComStatic.portalId);
???? prepstmt.executeUpdate();
?? prepstmt.close();
}
在執(zhí)行了一次executeQuery、executeUpdate等之后,如果不需要使用結(jié)果集(ResultSet)的數(shù)據(jù),就馬上將Statement或PreparedStatement關(guān)閉。
處理超出打開(kāi)游標(biāo)的最大數(shù)異常(ORA-01000: maximum open cursors exceeded)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
