Java開發中,使用Oracle數據庫的時候,經常會碰到有ORA-01000:?maximum?open?cursors?exceeded.的錯誤。?
實際上,這個錯誤的原因,主要還是代碼問題引起的。?
ORA-01000:?maximum?open?cursors?exceeded,表示已經達到一個進程打開的最大游標數。
?? 這樣的錯誤很容易出現在Java代碼中的主要原因是:Java代碼在執 行conn.createStatement()和conn.prepareStatement()的時候,實際上都是相當與在數據庫中打開了一個 cursor。尤其是,如果你的createStatement和prepareStatement是在一個循環里面的話,就會非常容易出現這個問題。因 為游標一直在不停的打開,而且沒有關閉。
一般來說,在寫Java代碼的時候,createStatement和prepareStatement都應該要放在循環外面,而且使用了這些 Statment后,及時關閉。最好是在執行了一次executeQuery、executeUpdate等之后,如果不需要使用結果集 (ResultSet)的數據,就馬上將Statment關閉。?
對于出現ORA-01000錯誤這種情況,單純的加大open_cursors并不是好辦法,那只是治標不治本。實際上,代碼中的隱患并沒有解除。?
而且,絕大部分情況下,open_cursors只需要設置一個比較小的值,就足夠使用了,除非有非常特別的要求。
二、分析
在循環里面每次都 stmt = con.createStatement(); 而沒有釋放,這樣每個都占用了一個服務器的游標資源,最后造成失敗
三、解決方案
1、增加關閉語句
?
2、將這句話移動到循環外面,推薦用這個
3、改裝成批量更新
四、總結
??? 鑒于上面的問題,在做基類的時候,在對數據進行DML操作的時候,盡量不要讓基類返回Statement,而應該在基類直接進行關閉。在做查詢的時候,可 以把statement留給程序員自己進行手動關閉,關閉的方法為:給ResultSet一個方法可以得到Statement,然后再關閉 Statement。個人認為這種方法是比較妥當的。
實際上,這個錯誤的原因,主要還是代碼問題引起的。?
ORA-01000:?maximum?open?cursors?exceeded,表示已經達到一個進程打開的最大游標數。
?? 這樣的錯誤很容易出現在Java代碼中的主要原因是:Java代碼在執 行conn.createStatement()和conn.prepareStatement()的時候,實際上都是相當與在數據庫中打開了一個 cursor。尤其是,如果你的createStatement和prepareStatement是在一個循環里面的話,就會非常容易出現這個問題。因 為游標一直在不停的打開,而且沒有關閉。
一般來說,在寫Java代碼的時候,createStatement和prepareStatement都應該要放在循環外面,而且使用了這些 Statment后,及時關閉。最好是在執行了一次executeQuery、executeUpdate等之后,如果不需要使用結果集 (ResultSet)的數據,就馬上將Statment關閉。?
對于出現ORA-01000錯誤這種情況,單純的加大open_cursors并不是好辦法,那只是治標不治本。實際上,代碼中的隱患并沒有解除。?
而且,絕大部分情況下,open_cursors只需要設置一個比較小的值,就足夠使用了,除非有非常特別的要求。
oracle?9i?默認的open_cursors=300??
一、看有問題的代碼
?1?import?java.sql.Connection;
?2?import?java.sql.DriverManager;
?3?import?java.sql.SQLException;
?4?import?java.sql.Statement;
?5?
?6?public?class?Test?{
?7???public?Connection?getConnection()?{
?8?????String?url?=?"jdbc:oracle:thin:@localhost:1521:ora9i";
?9?????String?user?=?"scott";
10?????String?password?=?"tiger";
11?????Connection?con?=?null;
12?????try?{
13???????Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
14???????con?=?DriverManager.getConnection(url,?user,?password);
15?????}?catch?(Exception?e)?{
16???????e.printStackTrace();
17?????}
18?????return?con;
19???}
20?
21???public?static?void?main(String[]?args)?throws?SQLException?{
22?????long?a?=?13819100000L;
23?????long?b?=?13819100600L;?//?問題點
24?????Connection?con?=?null;
25?????Statement?stmt?=?null;
26?????Test?insert?=?new?Test();
27?????try?{
28???????con?=?insert.getConnection();
29???????for?(long?c?=?a;?c?<=?b;?c++)?{
30?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
31?????????stmt?=?con.createStatement();?//?這里是問題的所在
32?????????stmt.executeUpdate(sql);
33???????}
34???????System.out.println("OK");
35?????}?catch?(Exception?e)?{
36???????e.printStackTrace();
37?????}?finally?{
38???????if?(con?!=?null)?{
39?????????con.close();
40???????}
41?????}
42???}
43?}
?2?import?java.sql.DriverManager;
?3?import?java.sql.SQLException;
?4?import?java.sql.Statement;
?5?
?6?public?class?Test?{
?7???public?Connection?getConnection()?{
?8?????String?url?=?"jdbc:oracle:thin:@localhost:1521:ora9i";
?9?????String?user?=?"scott";
10?????String?password?=?"tiger";
11?????Connection?con?=?null;
12?????try?{
13???????Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
14???????con?=?DriverManager.getConnection(url,?user,?password);
15?????}?catch?(Exception?e)?{
16???????e.printStackTrace();
17?????}
18?????return?con;
19???}
20?
21???public?static?void?main(String[]?args)?throws?SQLException?{
22?????long?a?=?13819100000L;
23?????long?b?=?13819100600L;?//?問題點
24?????Connection?con?=?null;
25?????Statement?stmt?=?null;
26?????Test?insert?=?new?Test();
27?????try?{
28???????con?=?insert.getConnection();
29???????for?(long?c?=?a;?c?<=?b;?c++)?{
30?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
31?????????stmt?=?con.createStatement();?//?這里是問題的所在
32?????????stmt.executeUpdate(sql);
33???????}
34???????System.out.println("OK");
35?????}?catch?(Exception?e)?{
36???????e.printStackTrace();
37?????}?finally?{
38???????if?(con?!=?null)?{
39?????????con.close();
40???????}
41?????}
42???}
43?}
二、分析
在循環里面每次都 stmt = con.createStatement(); 而沒有釋放,這樣每個都占用了一個服務器的游標資源,最后造成失敗
三、解決方案
1、增加關閉語句
?
1???con?=?insert.getConnection();
2???????for?(long?c?=?a;?c?<=?b;?c++)?{
3?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
4?????????stmt?=?con.createStatement();?//?這里是問題的所在
5?????????stmt.executeUpdate(sql);
6?????????stmt.close();?//?用完了就關閉好了
7???????}
2???????for?(long?c?=?a;?c?<=?b;?c++)?{
3?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
4?????????stmt?=?con.createStatement();?//?這里是問題的所在
5?????????stmt.executeUpdate(sql);
6?????????stmt.close();?//?用完了就關閉好了
7???????}
2、將這句話移動到循環外面,推薦用這個
1?con?=?insert.getConnection();
2???????stmt?=?con.createStatement();?//?移動到這里,Statemet是可以重用的
3???????for?(long?c?=?a;?c?<=?b;?c++)?{
4?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
5?????????stmt.executeUpdate(sql);
6???????}
7???????stmt.close();?//?用完了就關閉好了
2???????stmt?=?con.createStatement();?//?移動到這里,Statemet是可以重用的
3???????for?(long?c?=?a;?c?<=?b;?c++)?{
4?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
5?????????stmt.executeUpdate(sql);
6???????}
7???????stmt.close();?//?用完了就關閉好了
3、改裝成批量更新
1?con?=?insert.getConnection();
2???????con.setAutoCommit(false);
3???????stmt?=?con.createStatement();?//?移動到這里,Statemet是可以重用的
4???????for?(long?c?=?a;?c?<=?b;?c++)?{
5?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
6?????????stmt.addBatch(sql);
7???????}
8???????stmt.executeBatch();
9???????con.commit();
2???????con.setAutoCommit(false);
3???????stmt?=?con.createStatement();?//?移動到這里,Statemet是可以重用的
4???????for?(long?c?=?a;?c?<=?b;?c++)?{
5?????????String?sql?=?"insert?into?telepnum?values("?+?c?+?")";
6?????????stmt.addBatch(sql);
7???????}
8???????stmt.executeBatch();
9???????con.commit();
四、總結
??? 鑒于上面的問題,在做基類的時候,在對數據進行DML操作的時候,盡量不要讓基類返回Statement,而應該在基類直接進行關閉。在做查詢的時候,可 以把statement留給程序員自己進行手動關閉,關閉的方法為:給ResultSet一個方法可以得到Statement,然后再關閉 Statement。個人認為這種方法是比較妥當的。