Collus

          惜秦懷古

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            0 Posts :: 6 Stories :: 0 Comments :: 0 Trackbacks
          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只需要設置一個比較小的值,就足夠使用了,除非有非常特別的要求。

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

          二、分析

          在循環里面每次都 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、將這句話移動到循環外面,推薦用這個
          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();?//?用完了就關閉好了

          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();


          四、總結

          ??? 鑒于上面的問題,在做基類的時候,在對數據進行DML操作的時候,盡量不要讓基類返回Statement,而應該在基類直接進行關閉。在做查詢的時候,可 以把statement留給程序員自己進行手動關閉,關閉的方法為:給ResultSet一個方法可以得到Statement,然后再關閉 Statement。個人認為這種方法是比較妥當的。
          posted on 2010-04-16 20:37 良帥 閱讀(2405) 評論(0)  編輯  收藏 所屬分類: ORACLE

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 冷水江市| 苏尼特右旗| 沁阳市| 自贡市| 新沂市| 安陆市| 辽阳县| 清涧县| 金华市| 阿拉善右旗| 贵德县| 兴文县| 博客| 青岛市| 长沙市| 宣武区| 南漳县| 临澧县| 日喀则市| 唐山市| 密山市| 巴林右旗| 肃南| 赤城县| 乳源| 中西区| 元朗区| 贵港市| 衡山县| 喀喇沁旗| 宜兰县| 盐边县| 武邑县| 富蕴县| 阳新县| 山阴县| 利津县| 宁城县| 临泉县| 玛曲县| 淮安市|