Versuchen Sie, eine Quelle zu schreiben, die einen Trick und einen ORA-1000-Fehler in einer Bindungsvariablen SQL verursacht, die Javas PreparedStatement verwendet, um eine Problemumgehung zu finden.

ORA-1000-Fehler in Oracle-Datenbanksitzung geöffnet Dieser Fehler tritt auf, wenn die Anzahl der Cursor den Maximalwert überschreitet.

ORA-1000 Die maximale Anzahl offener Cursor wurde überschritten.

Vorbereitung

Versuchen wir es sofort. 彡 (゜) (゜) Bereiten Sie zuerst den Tisch vor.

CREATE TABLE TBL_A(
    C1 NUMBER
  , C2 VARCHAR2(30)
);

Java-Quelle, die einen ORA-1000-Fehler verursacht (* Anti-Pattern)

In SQL, einer Bindungsvariablen von PreparedStatement, Die Quelle ist so geschrieben, dass Tricks und ORA-1000-Fehler auftreten.

In der for-Schleife befindet sich eine prepareStatement-Methode, und der Cursor wird jedes Mal bewegt. Es wird neu geöffnet und es tritt ein Fehler auf. 彡 (゚) (゚)

Es ist voller verdammter Codeelemente, aber wenn ich Masakari überspringe (Akan 彡 (-) (-)

import java.sql.*;
import java.util.Date;

public class InsertTest {
    public static void main(String[] args) throws Exception {
        //DB connection info
        final String path = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";  //path
        final String id = "xxxxxxxx";  //ID
        final String pw = "yyyyyyyy";  //password
        int i;
        Connection conn = null;
        PreparedStatement ps = null;

        System.out.println(new Date() + " Connect...");
        try {
            //DB Connect
            conn = DriverManager.getConnection(path, id, pw);
            //AutoCommit Setting
            conn.setAutoCommit(false);
            //Insert Execute
            System.out.println(new Date() + " Insert...");
            for (i = 1; i <= 2000; i++) {
                //Prepared Statement Set.
                ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
                ps.setInt(1, i);
                ps.setString(2, "A" + String.valueOf(i));
                ps.execute();
            }
            //Commit
            conn.commit();
            //Close
            conn.close();
        } catch(SQLException ex) {
            conn.rollback();
            ex.printStackTrace();
            System.exit(1);
        } finally {
            if (ps != null) { ps.close(); }
            if (conn != null) { conn.close(); }
        }
        //End
        System.out.println(new Date() + " End...");
    }
}

Bei der Ausführung tritt der folgende ORA-1000-Fehler auf: 彡 (゚) (゚)

$ javac ./InsertTest.java
$ java -classpath .:${ORACLE_HOME}/jdbc/lib/ojdbc8.jar InsertTest
Thu Nov 30 00:57:01 JST 2017 Connect...
Thu Nov 30 00:57:23 JST 2017 Insert...
java.sql.SQLException: ORA-01000: maximum open cursors exceeded

        at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:494)
        at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:446)
        at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1054)
        at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:623)
        at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:252)
        at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:612)
        at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:226)
        at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:59)
        at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:910)
        at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1119)
        at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3780)
        at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1343)
        at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3887)
        at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1079)
        at InsertTest.main(InsertTest.java:27)
Caused by: Error : 1000, Position : 0, Sql = INSERT INTO TBL_A (C1, C2) VALUES (:1 , :2 ), OriginalSql = INSERT INTO TBL_A (C1, C2) VALUES (?, ?), Error Msg = ORA-01000: maximum open cursors exceeded

        at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:498)
        ... 14 more
$ echo $?
1

Problemumgehung 1. Platzieren Sie das prepareStatement außerhalb der for-Schleife.

Wenn Sie das prepareStatement außerhalb der for-Schleife platzieren, Sie können den ORA-1000-Fehler vermeiden. Ist das so? 彡 (゜) (゜)

:
//Insert Execute
System.out.println(new Date() + " Insert...");
//Prepared Statement Set.
ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
for (i = 1; i <= 2000; i++) {
    ps.setInt(1, i);
    ps.setString(2, "A" + String.valueOf(i));
    ps.execute();
}
//Commit
conn.commit();
:

Problemumgehung 2. Überprüfen Sie das Objekt auf null und führen Sie prepareStatement nur zum ersten Mal aus.

Nullprüfung des Objekts und des ersten prepareStatements Wenn Sie dies tun, können Sie den ORA-1000-Fehler vermeiden.

:
//Insert Execute
System.out.println(new Date() + " Insert...");
for (i = 1; i <= 2000; i++) {
    //Prepared Statement Set.
    if (ps == null) {
        ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
    }
    ps.setInt(1, i);
    ps.setString(2, "A" + String.valueOf(i));
    ps.execute();
}
//Commit
conn.commit();
:

Problemumgehung 3. Übernehmen Sie die Syntax "Try-with-Resources".

Es wird eine Variation der Problemumgehung 1 sein. 彡 (゚) (゚) Wenn Sie die im vorherigen Artikel beschriebene Try-with-Resources-Syntax verwenden, Vermeiden Sie das erste Anti-Pattern-Schreiben "natürlich" ORA-1000-Fehler tritt nicht auf. Der Punkt ist "natürlich".

Die Quelle ist sauber und alle guten Dinge sind 彡 (゚) (゚)

import java.sql.*;
import java.util.Date;

public class InsertTest {
    public static void main(String[] args) {
        //DB connection info
        final String path = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";  //path
        final String id = "xxxxxxxx";  //ID
        final String pw = "yyyyyyyy";  //password

        //try-with-resources Statement
        System.out.println(new Date() + " Connect...");
        try (
            //DB Connect
            Connection conn = DriverManager.getConnection(path, id, pw);
            //Prepared Statement Set.
            PreparedStatement ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
        ) {
            //Initialize
            int i;
            //AutoCommit Setting
            conn.setAutoCommit(false);
            //Insert Execute
            System.out.println(new Date() + " Insert...");
            for (i = 1; i <= 2000; i++) {
                ps.setInt(1, i);
                ps.setString(2, "A" + String.valueOf(i));
                ps.execute();
            }
            //Commit
            conn.commit();
        } catch(SQLException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
        //End
        System.out.println(new Date() + " End...");
    }
}

Problemumgehung 4. Schließen Sie jedes Mal das PreparedStatement-Objekt (). * Hinzugefügt am 27.11.2017

PreparedStatement-Objekt in einer Schleife Sie können den ORA-1000-Fehler vermeiden, indem Sie jedes Mal () schließen.

:
//Insert Execute
System.out.println(new Date() + " Insert...");
for (i = 1; i <= 2000; i++) {
    //Prepared Statement Set.
    ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
    ps.setInt(1, i);
    ps.setString(2, "A" + String.valueOf(i));
    ps.execute();
    ps.close();
}
//Commit
conn.commit();
:

Ist es schwierig, jedes Mal zu analysieren, wenn ich so schreibe? Ich dachte, Hard Parse kann jedes Mal mit der Anweisungs-Cache-Funktion 彡 (゚) (゚) vermieden werden.

Informationen zum Anweisungscache https://docs.oracle.com/cd/E16338_01/java.112/b56281/stmtcach.htm#i1069942 : -Vermeidet wiederholte Analyse und Bildung von Sätzen. :

Bonus (* Hinzugefügt am 30.11.2017)

Eine andere Person fragte: "Ist der Umfang der Variablen im Anti-Pattern nicht überhaupt seltsam?" Ich wurde darauf hingewiesen, also wenn ich die Quelle ändere, um die Variable in der try-Klausel zu deklarieren ... Nun, es wird natürlich ein Workaround 1.-ähnlicher Code. Die Try-with-Resources-Syntax ist wichtig, nicht wahr? (゜) (゜)

import java.sql.*;
import java.util.Date;

public class InsertTest {
    public static void main(String[] args) {
        //DB connection info
        final String path = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";  //path
        final String id = "xxxxxxxx";  //ID
        final String pw = "yyyyyyyy";  //password

        System.out.println(new Date() + " Connect...");
        try {
            //Init
            int i;
            //DB Connect
            Connection conn = DriverManager.getConnection(path, id, pw);
            //AutoCommit Setting
            conn.setAutoCommit(false);
            //Prepared Statement Set.
            PreparedStatement ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
            //Insert Execute
            System.out.println(new Date() + " Insert...");
            for (i = 1; i <= 2000; i++) {
                ps.setInt(1, i);
                ps.setString(2, "A" + String.valueOf(i));
                ps.execute();
            }
            //Commit
            conn.commit();
            //Close
            ps.close();
            conn.close();
        } catch(SQLException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
        //End
        System.out.println(new Date() + " End...");
    }
}

Bonus 2. Führen Sie SQL mit addBatch () und executeBatch () aus (* Hinzugefügt am 20.08.2019)

Ich habe in den Kommentaren einen Kommentar zu addBatch erhalten, daher habe ich ihn basierend auf der zusätzlichen Quelle geändert. Ich frage mich, ob es so in Ordnung ist ... 彡 (゚) (゚) Das Handbuch für addBatch (Batch-Update) ist [hier](https://docs.oracle.com/cd/F19136_01/jjdbc/performance-extensions.html#GUID -FEECA64F-44F4-453F-B8A8-AFBF6D29ABA4)

import java.sql.*;
import java.util.Date;

public class InsertTest {
    public static void main(String[] args) {
        //DB connection info
        final String path = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";  //path
        final String id = "xxxxxxxx";  //ID
        final String pw = "yyyyyyyy";  //password

        System.out.println(new Date() + " Connect...");
        try {
            //Init
            int i;
            //DB Connect
            Connection conn = DriverManager.getConnection(path, id, pw);
            //AutoCommit Setting
            conn.setAutoCommit(false);
            //Prepared Statement Set.
            PreparedStatement ps = conn.prepareStatement("INSERT INTO TBL_A (C1, C2) VALUES (?, ?)");
            //Insert Execute
            System.out.println(new Date() + " Insert...");
            for (i = 1; i <= 2000; i++) {
                ps.setInt(1, i);
                ps.setString(2, "A" + String.valueOf(i));
                ps.addBatch();
            }
            //Execute(batch updates)
            int[] updateCounts = ps.executeBatch();
            System.out.println(new Date() + " Batch Counts..." + updateCounts.length);
            //Commit
            conn.commit();
            //Close
            ps.close();
            conn.close();
        } catch(SQLException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
        //End
        System.out.println(new Date() + " End...");
    }
}
$ javac ./InsertTest.java
$ java -classpath .:/u01/app/oracle/product/version/db_1/jdbc/lib/ojdbc8.jar InsertTest
Tue Aug 20 04:18:11 EDT 2019 Connect...
Tue Aug 20 04:18:13 EDT 2019 Insert...
Tue Aug 20 04:18:14 EDT 2019 Batch Counts...2000
Tue Aug 20 04:18:14 EDT 2019 End...
$

Recommended Posts

Versuchen Sie, eine Quelle zu schreiben, die einen Trick und einen ORA-1000-Fehler in einer Bindungsvariablen SQL verursacht, die Javas PreparedStatement verwendet, um eine Problemumgehung zu finden.
[Docker] Wie man mit einem Container in Heroku aktualisiert und wie man mit Migrate Error umgeht
Memo zum stillen Schreiben der Quelle, die brauchbar zu sein scheint, und das Ergebnis der Kompilierung Execution-Java