sql >> データベース >  >> RDS >> Sqlserver

JDBCを使用してストアドプロシージャから*すべて*を取り戻す方法

    JDBCでストアドプロシージャを実行すると、一連の0個以上の「結果」が返されます。次に、CallableStatement#getMoreResults()を呼び出すことで、これらの「結果」を順番に処理できます。 。各「結果」には

    を含めることができます
    • ResultSetで取得できるデータの0行以上 オブジェクト、
    • CallableStatement#getUpdateCount()で取得できるDMLステートメント(INSERT、UPDATE、DELETE)の更新カウント 、または
    • SQLServerExceptionをスローするエラー。

    「問題1」の場合、多くの場合、ストアドプロシージャがSET NOCOUNT ON;で始まらないことが問題になります。 そして、SELECTを実行して結果セットを生成する前にDMLステートメントを実行します。 DMLの更新カウントは最初の「結果」として返され、getMoreResultsを呼び出すまで、データ行は「その背後に留まります」。 。

    「問題2」は本質的に同じ問題です。ストアドプロシージャは、エラーが発生する前に「結果」(通常はSELECT、場合によっては更新カウント)を生成します。エラーは後続の「結果」で返され、getMoreResultsを使用して「取得」するまで例外は発生しません。 。

    多くの場合、SET NOCOUNT ON;を追加するだけで問題を回避できます。 ストアドプロシージャの最初の実行可能ステートメントとして。ただし、ストアドプロシージャへの変更が常に可能であるとは限らず、すべてを取得するために事実が残っています。 ストアドプロシージャから戻って、getMoreResultsを呼び出し続ける必要があります Javadocが言うように:

    There are no more results when the following is true: 
    
         // stmt is a Statement object
         ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
    

    それは簡単に聞こえますが、次の例に示すように、いつものように「悪魔は細部に宿っています」。 SQLServerストアドプロシージャの場合...

    ALTER PROCEDURE dbo.TroublesomeSP AS
    BEGIN
        -- note: no `SET NOCOUNT ON;`
        DECLARE @tbl TABLE (id VARCHAR(3) PRIMARY KEY);
    
        DROP TABLE NonExistent;
        INSERT INTO @tbl (id) VALUES ('001');
        SELECT id FROM @tbl;
        INSERT INTO @tbl (id) VALUES ('001');  -- duplicate key error
        SELECT 1/0;  -- error _inside_ ResultSet
        INSERT INTO @tbl (id) VALUES ('101');
        INSERT INTO @tbl (id) VALUES ('201'),('202');
        SELECT id FROM @tbl;
    END
    

    ...次のJavaコードはすべてを返します...

    try (CallableStatement cs = conn.prepareCall("{call dbo.TroublesomeSP}")) {
        boolean resultSetAvailable = false;
        int numberOfResultsProcessed = 0;
        try {
            resultSetAvailable = cs.execute();
        } catch (SQLServerException sse) {
            System.out.printf("Exception thrown on execute: %s%n%n", sse.getMessage());
            numberOfResultsProcessed++;
        }
        int updateCount = -2;  // initialize to impossible(?) value
        while (true) {
            boolean exceptionOccurred = true; 
            do {
                try {
                    if (numberOfResultsProcessed > 0) {
                        resultSetAvailable = cs.getMoreResults();
                    }
                    exceptionOccurred = false;
                    updateCount = cs.getUpdateCount();
                } catch (SQLServerException sse) {
                    System.out.printf("Current result is an exception: %s%n%n", sse.getMessage());
                }
                numberOfResultsProcessed++;
            } while (exceptionOccurred);
    
            if ((!resultSetAvailable) && (updateCount == -1)) {
                break;  // we're done
            }
    
            if (resultSetAvailable) {
                System.out.println("Current result is a ResultSet:");
                try (ResultSet rs = cs.getResultSet()) {
                    try {
                        while (rs.next()) {
                            System.out.println(rs.getString(1));
                        }
                    } catch (SQLServerException sse) {
                        System.out.printf("Exception while processing ResultSet: %s%n", sse.getMessage());
                    }
                }
            } else {
                System.out.printf("Current result is an update count: %d %s affected%n",
                        updateCount,
                        updateCount == 1 ? "row was" : "rows were");
            }
            System.out.println();
        }
        System.out.println("[end of results]");
    }
    

    ...次のコンソール出力を生成します:

    Exception thrown on execute: Cannot drop the table 'NonExistent', because it does not exist or you do not have permission.
    
    Current result is an update count: 1 row was affected
    
    Current result is a ResultSet:
    001
    
    Current result is an exception: Violation of PRIMARY KEY constraint 'PK__#314D4EA__3213E83F3335971A'. Cannot insert duplicate key in object '[email protected]'. The duplicate key value is (001).
    
    Current result is a ResultSet:
    Exception while processing ResultSet: Divide by zero error encountered.
    
    Current result is an update count: 1 row was affected
    
    Current result is an update count: 2 rows were affected
    
    Current result is a ResultSet:
    001
    101
    201
    202
    
    [end of results]
    



    1. SQLデータベースにアラビア語を保存する

    2. MariaDBのストレージエンジンオプションの調査

    3. PGConfIndia2017を楽しみにしています

    4. MySQLソース-レプリカサーバーの重要なヘルスチェック